Within-host diversity and minor variant analyses in samples from
Houston Methodist Hospital, 2021
Sample characteristics and inclusion criteria
source("./scripts/startup.R")
The following packages are a base install and will not be unloaded:
The following packages were not previously loaded:
Loading required package: pacman
##### Load libraries and define recurring functions / variables
#all mcov samples we have ever received - reformat sample names to be consistent
mcov_samples_all <- fread("full_lineage_report_20220507.tsv", data.table=F) %>%
mutate(MCoVNumber=mcov_reformat(taxon)) %>%
filter(startsWith(MCoVNumber, "MCoV")) %>%
filter(MCoVNumber!="MCoV30904") #remove one sample with inconsistently formatted duplicates
#run and date info; keep only earliest sample from the same patient
mcov_info <- fread("sample_date_and_run.csv", data.table=F) %>%
mutate(COLLECTION_DT=as.Date(COLLECTION_DT, "%m/%d/%y"),
MCoVNumber=str_remove(mcov_id, "-")) %>%
arrange(COLLECTION_DT) %>% filter(!duplicated(PatientID))
#samples we received that we're interested in (December 2020-November 2021)
mcov_samples_1 <- mcov_samples_all %>% filter(!taxon %in% dup65.66) %>%
filter(MCoVNumber %in% mcov_info$MCoVNumber) %>% left_join(mcov_info)
Joining, by = "MCoVNumber"
#all samples sequenced in each run (including those from outside of this study period) -- sometimes relevant for run QC purposes
runs_all_samples <- fread("run_samples.csv", data.table = F) %>%
mutate(MCoVNumber=str_remove(`Sample ID`,"-"), run=Run) %>%
select(run, MCoVNumber)
#summary stats on coverage of each sample; drop the run 65 duplicates and join coverage info to main dataset
d1 = fread('coverage_levels_20220507.csv', data.table = F) %>%
filter(duplicated(samplename)) %>% pull(samplename)
d2 = fread('coverage_levels_20220507.csv', data.table = F) %>%
filter(samplename %in% d1) %>% filter(!duplicated(samplename)) %>%
pull(filename)
coverage_levels <- fread('coverage_levels_20220507.csv', data.table = F) %>%
filter(!filename %in% d2) %>% filter(samplename!="MCoV30904") %>% select(-1)
# join dataframes
mcov_samples<-mcov_samples_1 %>%
select(MCoVNumber, lineage, scorpio_call, qc_status,
COLLECTION_DT, INSTRUMENT, INSTRUMENT_RESULT, run=run_group) %>%
left_join(coverage_levels, by=c("MCoVNumber"="samplename"))
mcov_samples_with_ct<-mcov_samples %>% filter(INSTRUMENT_RESULT<50) %>%
mutate(CT=INSTRUMENT_RESULT)
#what's the relationship between CT value and read coverage?
coverage_all<-mcov_samples_with_ct %>% ggplot(aes(x=CT, y=median_coverage)) +
geom_point(alpha=0.07) + theme_bw() + xlab("Ct value") + ylab("Sample median depth")
#how does coverage in high-CT samples compare with the rest of them?
coverage_ct_cat<-mcov_samples_with_ct %>% mutate(sample_ct=if_else(CT>=40, "CT>=40", "CT<40")) %>%
ggplot(aes(x=sample_ct, y=median_coverage)) +
geom_point(alpha=0.2, position=position_jitter(width=0.25)) +
geom_boxplot(color="red", alpha=0) + theme_bw() +
xlab("Ct value") + ylab("Sample median depth")
Run-level QC
#are there any runs where high-CT samples have unusually high coverage? treat CT>40 samples as negative controls and eliminate runs where their coverage is not different from those of the rest of the samples
test_group<-mcov_samples_with_ct %>% mutate(is_neg=if_else(CT>=40,1,0)) %>%
group_by(run) %>% mutate(n_negs=sum(is_neg)) %>% filter(n_negs>=3) %>%
ungroup() %>% mutate(sampletype=if_else(is_neg==1, "negctrl","sample"))
runs_to_drop1 = test_group %>% group_by(run) %>%
summarise(t_test_p=t.test(fraction_1000x_coverage~sampletype)$p.value) %>%
arrange(desc(t_test_p)) %>% filter(t_test_p>0.01) %>% pull(run)
runs_to_drop2 = test_group %>% group_by(run) %>%
summarise(t_test_p=t.test(median_coverage~sampletype)$p.value) %>%
arrange(desc(t_test_p)) %>% filter(t_test_p>0.01) %>% pull(run)
############
runs_to_drop<-union(runs_to_drop1, runs_to_drop2)
saveRDS(runs_to_drop, "processing/runs_to_drop.rds")
mcov_samples_with_ct %>% pull(run) %>% unique()
[1] "Run_11" "Run_12" "Run_15" "Run_13" "Run_16" "Run_18" "Run_19" "Run_20" "Run_21" "Run_22" "Run_23"
[12] "Run_24" "Run_25" "Run_26" "Run_27" "Run_28" "Run_29" "Run_30" "Run_31" "Run_35" "Run_32" "Run_33"
[23] "Run_34" "Run_37" "Run_36" "Run_39" "Run_40" "Run_41" "Run_43" "Run_44" "Run_46" "Run_48" "Run_49"
[34] "Run_51" "Run_52" "Run_53" "Run_57" "Run_58" "Run_59" "Run_61" "Run_62" "Run_63" "Run_64" "Run_65"
[45] "Run_66" "Run_68" "Run_69" "Run_70" "Run_71" "Run_72" "Run_73" "Run_74" "Run_75" "Run_76" "Run_77"
[56] "Run_78" "Run_79" "Run_80" "Run_81" "Run_82" "Run_83" "Run_85" "Run_86" "Run_87" "Run_88" "Run_89"
[67] "Run_90" "Run_14" "Run_17"
test_group %>% group_by(run, sampletype) %>% summarize(counts = n()) %>%
filter(run %in% runs_to_drop) %>% nrow()
`summarise()` has grouped output by 'run'. You can override using the `.groups` argument.
[1] 44
mcov_samples_with_ct %>% pull(run) %>% unique()
[1] "Run_11" "Run_12" "Run_15" "Run_13" "Run_16" "Run_18" "Run_19" "Run_20" "Run_21" "Run_22" "Run_23"
[12] "Run_24" "Run_25" "Run_26" "Run_27" "Run_28" "Run_29" "Run_30" "Run_31" "Run_35" "Run_32" "Run_33"
[23] "Run_34" "Run_37" "Run_36" "Run_39" "Run_40" "Run_41" "Run_43" "Run_44" "Run_46" "Run_48" "Run_49"
[34] "Run_51" "Run_52" "Run_53" "Run_57" "Run_58" "Run_59" "Run_61" "Run_62" "Run_63" "Run_64" "Run_65"
[45] "Run_66" "Run_68" "Run_69" "Run_70" "Run_71" "Run_72" "Run_73" "Run_74" "Run_75" "Run_76" "Run_77"
[56] "Run_78" "Run_79" "Run_80" "Run_81" "Run_82" "Run_83" "Run_85" "Run_86" "Run_87" "Run_88" "Run_89"
[67] "Run_90" "Run_14" "Run_17"
test_group %>% group_by(run, sampletype) %>% summarize(counts = n()) %>%
filter(sampletype=="negctrl") %>% arrange(counts) %>% mutate(dropped = run %in% runs_to_drop) %>%
ggplot(aes(dropped,counts, label=run)) + geom_boxplot() + geom_point() + geom_text_repel() + theme_pubr()
`summarise()` has grouped output by 'run'. You can override using the `.groups` argument.

runs_kept = mcov_samples_with_ct$run[!mcov_samples_with_ct$run %in% runs_to_drop] %>% unique()
f1 = mcov_samples_with_ct %>% mutate(run_kept = run %in% runs_kept) %>%
ggplot(aes(INSTRUMENT_RESULT, fraction_1000x_coverage,
color = run_kept)) +
geom_point(shape=".", alpha = 0.5) + theme_pubr() +
theme(plot.title = element_text(size = 40, face = "bold")) +
geom_vline(xintercept=40, color = "red") + geom_smooth()
f1

f2 = mcov_samples_with_ct %>% mutate(run_kept = run %in% runs_kept) %>%
ggplot(aes(INSTRUMENT_RESULT, log10(median_coverage), color = run_kept)) +
geom_point(shape=".", alpha = 0.5) + theme_pubr() +
theme(plot.title = element_text(size = 40, face = "bold")) +
geom_vline(xintercept=40, color = "red") + geom_smooth()
runs_samples_dots = ggarrange(f1, f2, ncol = 1, nrow = 2, align = "v", common.legend = T)
`geom_smooth()` using method = 'gam' and formula = 'y ~ s(x, bs = "cs")'`geom_smooth()` using method = 'gam' and formula = 'y ~ s(x, bs = "cs")'`geom_smooth()` using method = 'gam' and formula = 'y ~ s(x, bs = "cs")'
runs_samples_dots
ggsave("ggsave/runs_samples_dots.pdf", plot = runs_samples_dots, width = 3, height = 4.5)

mcov_samples_with_ct %>% colnames()
[1] "MCoVNumber" "lineage" "scorpio_call"
[4] "qc_status" "COLLECTION_DT" "INSTRUMENT"
[7] "INSTRUMENT_RESULT" "run" "fraction_100x_coverage"
[10] "fraction_200x_coverage" "fraction_500x_coverage" "fraction_1000x_coverage"
[13] "median_coverage" "CT"
### plot boxplot of the runs
stmp = mcov_samples_with_ct %>% mutate(run_dropped = run %in%
runs_to_drop) %>% mutate(run = as.numeric(gsub("Run_", "", run))) %>%
mutate(is_neg=if_else(CT>=40,1,0))
label_at <- function(n) function(x) ifelse(x %% n == 0, x, "")
f3 = ggplot(stmp, aes(x=run, y=fraction_1000x_coverage, group = run,
color = run_dropped, fill = run_dropped)) +
geom_boxplot() +
geom_point(data = stmp %>% filter(is_neg == T),
aes(run, fraction_1000x_coverage), color = "red", alpha = .9,
shape = 1) +
scale_fill_grey(start = 1, end = 0.8) +
scale_x_continuous(breaks = seq(10,90,2), limits = c(10,92), labels = label_at(10)) +
scale_color_grey(start=0, end=0.6) +
theme(axis.text.x = element_text(angle = 90, vjust = .5)) +
labs( x = NULL)
f4 = ggplot(stmp, aes(x=run, y=log10(median_coverage), group = run,
color = run_dropped, fill = run_dropped)) +
geom_boxplot() +
geom_point(data = stmp %>% filter(is_neg == T),
aes(run, log10(median_coverage)), color = "red", alpha = .9,
shape = 1) +
scale_fill_grey(start = 1, end = 0.8) +
scale_x_continuous(breaks = seq(10,90,2), limits = c(10,92), labels = label_at(10)) +
scale_color_grey(start=0, end=0.6) +
theme(axis.text.x = element_text(angle = 90, vjust = .5)) +
labs( x = NULL)
run_filter_red = ggarrange(f3, f4, ncol = 1, nrow = 2, align = "v", common.legend = T)
((
run_filter_red_plot = annotate_figure(run_filter_red,
top = text_grob("red circles: samples Ct>40", color = "red", size = 10))
))

ggsave("ggsave/run_filter_red_plot.pdf", plot = run_filter_red_plot, width = 6, height = 4)

Sample-level QC
#nextclade QC
nc<-fread("houston_nextclade.tsv", sep='\t', data.table = F) %>%
mutate(MCoVNumber=regmatches(seqName, regexpr("[M,R,S,O]CoV.[0-9]+", seqName)) %>%
str_remove("-") %>% str_remove("_")) %>% filter(!duplicated(MCoVNumber))
nextclade_bad_samples<-nc %>% filter(qc.overallStatus %in% c("bad")) %>% pull(MCoVNumber)
#drop bad runs and samples that don't pass pangolin QC or nextclade QC
mcov_samples_filtered<-mcov_samples %>% filter(!run %in% runs_to_drop) %>%
filter(qc_status=="pass") %>% filter(!MCoVNumber %in% nextclade_bad_samples) %>%
filter(scorpio_call!="Omicron (BA.1-like)") %>%
##### #main coverage criterion for fair comparisons: X depth over Y percent of the genome
filter(fraction_100x_coverage>=0.98) %>% droplevels()
#what's the distribution of CT values?
ct_distribution_after_qc<-mcov_samples_filtered %>% filter(INSTRUMENT_RESULT<50) %>%
ggplot(aes(x=INSTRUMENT_RESULT)) + geom_histogram(binwidth=1) + theme_bw() +
xlab("Ct value") + labs(caption="After exclusion criteria")
#How did exclusion criteria change distribution of sample Ct values?
ct_distribution_after_qc<-mcov_samples_filtered %>% filter(INSTRUMENT_RESULT<50) %>% ggplot(aes(x=INSTRUMENT_RESULT)) + geom_histogram(binwidth=1) + theme_bw() + xlab("Ct value")
ct_distribution_before_qc<-mcov_samples %>% filter(INSTRUMENT_RESULT<50) %>% ggplot(aes(x=INSTRUMENT_RESULT)) + geom_histogram(binwidth=1) + theme_bw() + xlab("Ct value") + labs(caption="Before exclusion criteria")
#ct_inclusion<-plot_grid(ct_distribution_before_qc, ct_distribution_after_qc, nrow=2)
#ct_inclusion
ct_distribution_after_qc<-mcov_samples_filtered %>% filter(INSTRUMENT_RESULT<50)
ct_distribution_before_qc<-mcov_samples %>% filter(INSTRUMENT_RESULT<50)
plot1_ct_before_after = ggplot(aes(x=INSTRUMENT_RESULT), data = ct_distribution_before_qc) +
geom_histogram(binwidth = 1, fill = "grey") +
geom_histogram(data = ct_distribution_after_qc, binwidth=1) + theme_pubr() +
xlab("Ct value") + ylab("# samples") #+ geom_vline(xintercept = 26,
# linetype = "dashed")
ggsave("ggsave/plot1_ct_before_after.pdf", plot1_ct_before_after, height = 2, width = 4)
Preliminary minor variant distributions
#nucleotide positions of all primers used in dataset; will exclude
primers = fread("nCoV-2019.artic_v3.primer.txt", sep="\t", header=FALSE, data.table=F) %>%
select(start = V2, end = V3)
primer_positions_v3<-as.numeric()
for (i in 1:nrow(primers)){
primer_positions_v3<-c(primer_positions_v3, primers[i,]$start:primers[i,]$end)
}
primers = fread("nCoV-2019.artic_v4.primer.bed", sep="\t",
header=FALSE, data.table = F) %>% select(start = V2, end = V3)
primer_positions_v4<-as.numeric()
for (i in 1:nrow(primers)){
primer_positions_v4<-c(primer_positions_v4, primers[i,]$start:primers[i,]$end)
}
problem_sites_global = fread("problematic_sites_sarsCov2_v8-20211027.vcf", skip = 88) %>%
filter(FILTER != "mask") %>%
filter(!grepl('single_src|nanopore', INFO)) %>% pull(POS)
problem_sites_houston = fread("problematic_sites_sarsCov2_v8-20211027.vcf", skip = 88) %>%
filter(grepl('Houston', INFO)) %>% pull(POS)
problem_sites = unique(c(problem_sites_global, problem_sites_houston))
primer_positions_all <- c(primer_positions_v3, primer_positions_v4, problem_sites) %>% unique()
# insert problem sites if necessary
saveRDS(primer_positions_all, "primer_positions_all.rds")
#reference genome with nucleotide positions of genes
genes <- fread("ntpos_gene_update.csv", data.table = F)
gene_names <- genes %>% pull(gene_id) %>% unique()
genes$gene_id <- factor(genes$gene_id, levels = gene_names)
### Update this if you change sample inclusion criteria
### Update this if change the thresholds for counting minor variants
#file was already filtered to sites with minimum 100 reads depth and A,C,T,G minor variant present and binomial significance check passed. Further filtering:
# depth_at_site<-100
# minor_frequency<-0.01
# total_minor_reads<-50
#
# minor_variant_sites_threshold <- fread("minor_sites_100x_all_20220507.csv") %>%
# mutate(MCoVNumber=regmatches(name,
# regexpr("[M,R,S,O]CoV.[0-9]+", name)) %>%
# str_remove("-") %>% str_remove("_")) %>%
# filter(!ntpos %in% primer_positions_all) %>% #don't include primer binding sites
# filter(MCoVNumber %in% mcov_samples_filtered$MCoVNumber) %>%
# filter(totalcount>=depth_at_site) %>%
# filter(!ntpos %in% c(1:265)) %>% filter(!ntpos>29674) %>% #don't include 5' and 3' UTR
# filter(major %in% c("A","C","T","G")) %>% #don't want minor variants at consensus deletion sites
# filter(minorfreq>=minor_frequency) %>%
# filter(minorfreq*totalcount>=total_minor_reads)
# write_feather(minor_variant_sites_threshold, 'processing/minor_variants_filtered_100x0.01_50.arrow')
Overall minor variant richness
source("./scripts/startup.R")
The following packages have been unloaded:
ggforestplot, doParallel, iterators, foreach, glmmTMB, broom, tableone, arrow, magrittr, scales, lubridate, ggExtra, ggsci, pheatmap, Biostrings, GenomeInfoDb, XVector, IRanges, S4Vectors, BiocGenerics, ggrepel, data.table, ggpubr, viridis, viridisLite, gggenes, ggforce, glmnet, Matrix, cowplot, forcats, stringr, dplyr, purrr, readr, tidyr, tibble, ggplot2, tidyverse, pacman
Loading required package: pacman
minor_variant_sites_threshold <- read_feather('processing/minor_variants_filtered_100x0.01_50.arrow')
n_var <- minor_variant_sites_threshold %>% group_by(MCoVNumber) %>% tally() %>% arrange(desc(n)) #this tally doesn't include any samples with 0 variants, so need to join to original list
samples_n_var <- mcov_samples_filtered %>% left_join(n_var) %>%
arrange(COLLECTION_DT) %>% mutate(n_var=tidyr::replace_na(n,0))
Joining, by = "MCoVNumber"
write_feather(samples_n_var, "processing/samples_n_var.arrow")
#what's the distribution of minor variant richness?
###
((
n_var_select <- samples_n_var %>% ggplot(aes(x=n_var)) +
geom_histogram(binwidth=5) + theme_pubr() +
xlab("No. minor variants in sample") + ylab("No. samples") +
scale_y_continuous(trans='log1p', breaks=c(1, 10, 100, 1000, 5000))
))

#what's the relationship between minor variant richness and Ct value?
n_var_select_ct = samples_n_var %>% filter(INSTRUMENT_RESULT<50) %>%
ggplot(aes(x=INSTRUMENT_RESULT, y=n_var)) +
geom_point(shape = 1, alpha = 1/8) +
geom_density_2d(alpha = 1/2, color = "red") +
scale_y_continuous(trans = "log1p", breaks = c(0,1,5,10,30,50,100,300,500)) +
scale_x_continuous(breaks = seq(0,40,by = 5)) +
theme_pubr() + xlab("Ct value") + ylab("n_var") +
geom_hline(yintercept = 30, linetype = "dashed") +
geom_vline(xintercept = 26, linetype = "dashed")
plot1_target = ggMarginal(n_var_select_ct, type = "violin", draw_quantiles =
c(.25,.5,.75))
ggsave("ggsave/plot1_target.pdf", plot = plot1_target, height = 3, width = 4)
((
n_var_select_ct_filtered = samples_n_var %>%
filter(INSTRUMENT_RESULT<26 & n_var < 30) %>%
ggplot(aes(x=INSTRUMENT_RESULT, y=n_var)) +
geom_point(shape = 1, alpha = 1/16) +
geom_density_2d(color = "salmon") +
scale_y_continuous(breaks = seq(0,30,5)) +
scale_x_continuous(breaks = seq(0,40,by = 5)) +
theme_pubr() + xlab("Ct value") + ylab("n_var") +
geom_smooth(color = "red") + stat_cor(method = "spearman", cor.coef.name = "rho")
))


patient_ordinal_counts = samples_n_var %>%
filter(INSTRUMENT_RESULT<26 & n_var < 30) %>%
mutate(ordinal_counts = cut(n_var, breaks = seq(0,30,5),
right = F)) %>%
select(n_var, ordinal_counts) %>% arrange(n_var) %>%
group_by(ordinal_counts) %>% summarize(counts = n()) %>%
mutate(position = seq(2.5,27.5,5))
n_var_select_ct_filtered_labeled = n_var_select_ct_filtered +
geom_text(aes(x=25, y = position, label = counts), color = "darkblue",
data = patient_ordinal_counts) +
theme_minimal_hgrid()
ct_n_var_postfilter_plot = ggMarginal(n_var_select_ct_filtered_labeled,
type = "violin",
draw_quantiles = c(0.25,0.5,0.75))
`geom_smooth()` using method = 'gam' and formula = 'y ~ s(x, bs = "cs")'`geom_smooth()` using method = 'gam' and formula = 'y ~ s(x, bs = "cs")'
ct_n_var_postfilter_plot

ggsave("ggsave/ct_n_var_postfilter_plot.pdf",
ct_n_var_postfilter_plot, height = 3, width = 3)
saveRDS(ct_n_var_postfilter_plot, "ct_n_var_postfilter_plot.rds")
# Quantile information for the violin plot above
print(samples_n_var %>%
filter(INSTRUMENT_RESULT<26 & n_var < 30) %>% pull(n_var) %>% quantile(.,probs = c(0,0.25,0.5,0.75)))
0% 25% 50% 75%
0 2 5 9
print(samples_n_var %>%
filter(INSTRUMENT_RESULT<26 & n_var < 30) %>% pull(INSTRUMENT_RESULT) %>% quantile(.,probs = c(0,0.25,0.5,0.75)))
0% 25% 50% 75%
6.67 15.80 18.42 21.39
samples_n_var %>% pull(n_var) %>% summary()
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.00 3.00 6.00 18.97 16.00 454.00
Reproducibility of minor variants
minors_table<- fread("replicated_samples.csv", data.table=F) %>%
filter(MCoVNumber %in% samples_n_var$MCoVNumber) %>%
filter(major.original %in% c("A","C","T","G")) %>%
filter(minor.original %in% c("A","C","T","G")) %>%
filter(totalcount.original>=100 & minorfreq.original>=0.01 & totalcount.original*minorfreq.original>=50 &
tolower(binocheck.original)!="false") %>% filter((!ntpos %in% primer_positions_all)) %>%
filter(!ntpos %in% 1:265) %>% filter(!ntpos>29674)
|--------------------------------------------------|
|==================================================|
#was the same minor variant found in the second replicate? if not, set minor frequency to 0 in second rep
minors_table<-minors_table %>%
mutate(minorfreq.reseq=if_else(minor.original==minor.reseq, minorfreq.reseq, 0)) %>%
mutate(detected_minor_in_repl=if_else(minor.original==minor.reseq,"yes","no"))
write_feather(minors_table, "processing/minors_table.arrow")
#how well are minor variants recovered in samples with different Ct values?
minors_table <- minors_table %>% left_join(select(mcov_samples, MCoVNumber, CT=INSTRUMENT_RESULT)) %>%
mutate(sampleCT_bin = case_when(CT<26 ~ "below 26",
CT>=26&CT<=35 ~"CT 26-35",
CT>35&CT<50 ~"greater than 35",
CT>100~"unknown", #aptima instrument uses RLU not CT
is.na(CT) ~ "unknown"))
Joining, by = "MCoVNumber"
((
rep_ct<-minors_table %>%
ggplot(aes(x=minorfreq.original, y=minorfreq.reseq, color=detected_minor_in_repl)) +
scale_color_manual(values=c("red","black")) + geom_point(alpha=0.5) +
facet_wrap(~sampleCT_bin) + theme_bw() + labs(x="MAF in replicate 1", y="MAF in replicate 2") +
theme(legend.position="bottom")
))

#how well are minor variants recovered in samples with different median coverage?
rep_depth <- minors_table %>% left_join(coverage_levels, by=c("MCoVNumber"="samplename")) %>%
mutate(coverage_bin=cut(median_coverage, 4)) %>%
ggplot(aes(x=minorfreq.original, y=minorfreq.reseq, color=detected_minor_in_repl)) +
scale_color_manual(values=c("red","black")) + geom_point(alpha=0.5) +
facet_wrap(~coverage_bin) + theme_bw() +
labs(x="MAF in replicate 1", y="MAF in replicate 2") +
theme(legend.position="none", axis.text.x = element_text(color=c(1,0,1,0))) +
labs(caption="Reproducibility in samples with different median depths")
Warning: Vectorized input to `element_text()` is not officially supported.
ℹ Results may be unexpected or may change in future versions of ggplot2.
#in the range of Ct values/coverage observed here, reproducibility seems more associated with Ct than with coverage
#what's the distribution of depth/MAF in reproducible vs. non-reproducible minor variants?
rep_depth_freq <- minors_table %>% ggplot(aes(x=totalcount.original, y=minorfreq.original)) +
geom_point(alpha=0.5) + facet_grid(detected_minor_in_repl~.) + theme_bw() +
theme(axis.text.x = element_text(color=c(1,0,1,0))) + xlab("Seq depth in rep 1") +
ylab("MAF in rep 1") + labs(caption="Reproducibility at sites with different depth and MAF")
Warning: Vectorized input to `element_text()` is not officially supported.
ℹ Results may be unexpected or may change in future versions of ggplot2.
#depth and frequency of minor variants is also not very different between reproducible and non-reproducible variants
rep_mutations <- minors_table %>% filter(detected_minor_in_repl=="yes")
nonrep_mutations <- minors_table %>% filter(detected_minor_in_repl=="no")
plot_reproducible_spectra_heatmap <- table(rep_mutations$major.original, rep_mutations$minor.original) %>%
data.frame() %>% ggplot(aes(x=Var1, y=Var2, fill=Freq/sum(Freq))) +
geom_tile(colour = "black") + # grid colour
scale_fill_gradient(low = "white",
high = "darkblue") +
theme_minimal() + labs(fill = "Fraction",
x = "Consensus allele",
y = "Minor allele", title="Reproducible")
plot_nonreproducible_spectra_heatmap <- table(nonrep_mutations$major.original,
nonrep_mutations$minor.original) %>%
data.frame() %>% ggplot(aes(x=Var1, y=Var2, fill=Freq/sum(Freq))) +
geom_tile(colour = "black") +
scale_fill_gradient(low = "white",
high = "darkblue") +
theme_minimal() + labs(fill = "Fraction",
x = "Consensus allele",
y = "Minor allele", title="Non-reproducible")
saveRDS(plot_nonreproducible_spectra_heatmap, file = "plot_nonreproducible_spectra_heatmap.rds")
saveRDS(plot_reproducible_spectra_heatmap, file = "plot_reproducible_spectra_heatmap.rds")
# Plotted in RMD 03.
rep_indiv_samples <- minors_table %>% ggplot(aes(x=minorfreq.original,
y=minorfreq.reseq,
color=detected_minor_in_repl)) +
geom_point(alpha=0.5) + scale_color_manual(values=c("red","black")) +
facet_wrap(CT~MCoVNumber) + theme_bw() + xlab("MAF in replicate 1") +
ylab("MAF in replicate 2") +
theme(legend.position="none", axis.text.x = element_text(color=c(1,0,1,0)))
Warning: Vectorized input to `element_text()` is not officially supported.
ℹ Results may be unexpected or may change in future versions of ggplot2.
#SUPP FIG 1
replicate_mega_plot = plot_grid(
plot_grid(rep_ct,
plot_grid(rep_depth, rep_depth_freq, ncol=2, rel_widths=c(1.2,1),
labels=c("b","c")), nrow=2, labels=c("a",NA)),
rep_indiv_samples, labels=c(NA, "d"), rel_widths=c(1.1,1))
Warning: Removed 1 rows containing missing values (`geom_text()`).
ggsave("ggsave/replicate_mega_plot.pdf", plot = replicate_mega_plot, height = 8, width = 14.5)
Will limit analyses to samples with CT<26, where we are more
confident in reproducibility of minor variant
samples_n_var %>% filter(INSTRUMENT_RESULT<26 & n_var < 30) %>% pull(n_var) %>% quantile(c(0.5,0.7))
50% 70%
5 7
samples_to_analyze <- samples_n_var %>% filter(INSTRUMENT_RESULT<26 & n_var < 30) %>% pull(MCoVNumber)
lineages_figure <- mcov_samples_filtered %>%
filter(MCoVNumber %in% samples_to_analyze) %>%
mutate(variant=case_when(startsWith(scorpio_call,"Delta") ~ "Delta",
startsWith(scorpio_call,"Alpha") ~ "Alpha",
!(startsWith(scorpio_call,"Delta")|
startsWith(scorpio_call,"Alpha")) ~ "other")) %>%
mutate(variant=if_else(lineage == "B.1.2","B.1.2",variant)) %>%
mutate(month = floor_date(COLLECTION_DT, "month")) %>%
ggplot(aes(x=month)) + geom_bar(aes(fill=variant)) +
# scale_fill_manual(values=c("#00A08A", "#F2AD00", "#F98400", "#5BBCD6")) +
xlab("Collection date") + ylab("No. samples") + scale_x_date(labels = date_format("%m-%Y")) +
ggtitle(paste0('Final sample set, \n Ct<26 & n_var<30, n = ',length(samples_to_analyze))) +
scale_x_date(minor_breaks="1 month") + theme_pubr() +
theme(axis.text.x = element_text(angle = 90, vjust = .5), legend.position = "top")
Scale for x is already present.
Adding another scale for x, which will replace the existing scale.
#SUPP FIG 2
lineages_figure

saveRDS(lineages_figure, "ggsave/lineages_figure.rds")
samples_n_var %>% filter(INSTRUMENT_RESULT<26) %>% pull(n_var) %>% summary()
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.0 2.0 5.0 10.8 10.0 380.0
#plot_grid(coverage_pre_filtering, ct_inclusion, ncol=2, labels=c("a","b"))
minor_sites_lowct<-minor_variant_sites_threshold %>% left_join(mcov_samples_filtered) %>%
filter(INSTRUMENT_RESULT<26)
Joining, by = "MCoVNumber"
What kinds of run-specific effects do we see even after filtering
for high-quality samples?
#are run effects related to sequencing depth?
n_var_by_coverage<-samples_n_var %>% filter(INSTRUMENT_RESULT<26 & n_var < 30) %>% ggplot(aes(x=median_coverage, y=n_var)) + geom_point(alpha=0.05) +
geom_density_2d(color = "salmon") + geom_smooth(color = "red") + theme_pubr() +
scale_x_continuous(limits = c(0, 15000)) +
xlab("Sample median coverage") + ylab("n_var") + stat_cor(method = "spearman", cor.coef.name = "rho")
n_var_by_coverage

#not on the individual sample level
#is average minor variant richness in a run related to average depth of coverage in the run?
n_var_depth_averages<-samples_n_var %>% filter(INSTRUMENT_RESULT<26 & n_var < 30) %>%
group_by(run) %>%
summarise(median_n_var=median(n_var),
median_sample_coverage=median(median_coverage),
median_ct=median(INSTRUMENT_RESULT)) %>%
ggplot(aes(x=median_sample_coverage, y=median_n_var)) + geom_point(alpha = 0.5) +
scale_x_continuous(limits = c(0, 15000)) +
theme_pubr() + xlab("Run median of median coverage") + ylab("Run median n_var") +
geom_smooth(color = "red") + stat_cor(method = "spearman", cor.coef.name = "rho")
n_var_depth_averages

n_var_by_run <- samples_n_var %>% mutate(run = as.numeric(str_remove(run, "Run_"))) %>%
filter(INSTRUMENT_RESULT < 26 & n_var < 30) %>%
ggplot(aes(x=run, y=n_var, group = run)) + geom_boxplot() +
scale_fill_grey(start = 1, end = 0.8) +
scale_x_continuous(breaks = seq(10,90,2), limits = c(10,92), labels = label_at(10)) +
scale_y_continuous(breaks = seq(0,30,2), labels = label_at(10)) +
scale_color_grey(start=0, end=0.6) +
theme(axis.text.x = element_text(angle = 90, vjust = .5))
plots_by_run = ggarrange(f3, f4, n_var_by_run, labels = list("A","B","D"),
ncol = 1, nrow = 3, align = "v", common.legend = T) %>% annotate_figure(.,
top = text_grob("red circles: samples Ct>40", color = "red", size = 10))
dots_depth_median = ggarrange(n_var_by_coverage, n_var_depth_averages,
labels = list("E", "F"), ncol = 1)
Warning: Removed 4 rows containing non-finite values (`stat_density2d()`).`geom_smooth()` using method = 'gam' and formula = 'y ~ s(x, bs = "cs")'Warning: Removed 4 rows containing non-finite values (`stat_smooth()`).Warning: Removed 4 rows containing non-finite values (`stat_cor()`).Warning: Removed 4 rows containing missing values (`geom_point()`).`geom_smooth()` using method = 'loess' and formula = 'y ~ x'
dots_plots = ggarrange(runs_samples_dots, dots_depth_median, labels = list("C"),
ncol = 1, heights = c(1,1))
run_filtration = ggarrange(plots_by_run, dots_plots, ncol = 2, widths = c(2.5, 1))
run_filtration


ggsave("ggsave/run_filtration.pdf", run_filtration, height = 8, width = 12)
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBodG1sX2RvY3VtZW50OgogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0Ci0tLQoKIyBXaXRoaW4taG9zdCBkaXZlcnNpdHkgYW5kIG1pbm9yIHZhcmlhbnQgYW5hbHlzZXMgaW4gc2FtcGxlcyBmcm9tIEhvdXN0b24gTWV0aG9kaXN0IEhvc3BpdGFsLCAyMDIxCgojIyBTYW1wbGUgY2hhcmFjdGVyaXN0aWNzIGFuZCBpbmNsdXNpb24gY3JpdGVyaWEgCgoKYGBge3J9CnNvdXJjZSgiLi9zY3JpcHRzL3N0YXJ0dXAuUiIpCgojIyMjIyBMb2FkIGxpYnJhcmllcyBhbmQgZGVmaW5lIHJlY3VycmluZyBmdW5jdGlvbnMgLyB2YXJpYWJsZXMKI2FsbCBtY292IHNhbXBsZXMgd2UgaGF2ZSBldmVyIHJlY2VpdmVkIC0gcmVmb3JtYXQgc2FtcGxlIG5hbWVzIHRvIGJlIGNvbnNpc3RlbnQKbWNvdl9zYW1wbGVzX2FsbCA8LSBmcmVhZCgiZnVsbF9saW5lYWdlX3JlcG9ydF8yMDIyMDUwNy50c3YiLCBkYXRhLnRhYmxlPUYpICU+JSAKICBtdXRhdGUoTUNvVk51bWJlcj1tY292X3JlZm9ybWF0KHRheG9uKSkgJT4lIAogIGZpbHRlcihzdGFydHNXaXRoKE1Db1ZOdW1iZXIsICJNQ29WIikpICU+JSAKICBmaWx0ZXIoTUNvVk51bWJlciE9Ik1Db1YzMDkwNCIpICNyZW1vdmUgb25lIHNhbXBsZSB3aXRoIGluY29uc2lzdGVudGx5IGZvcm1hdHRlZCBkdXBsaWNhdGVzCgojcnVuIGFuZCBkYXRlIGluZm87IGtlZXAgb25seSBlYXJsaWVzdCBzYW1wbGUgZnJvbSB0aGUgc2FtZSBwYXRpZW50Cm1jb3ZfaW5mbyA8LSBmcmVhZCgic2FtcGxlX2RhdGVfYW5kX3J1bi5jc3YiLCBkYXRhLnRhYmxlPUYpICU+JSAKICBtdXRhdGUoQ09MTEVDVElPTl9EVD1hcy5EYXRlKENPTExFQ1RJT05fRFQsICIlbS8lZC8leSIpLAogICAgICAgICBNQ29WTnVtYmVyPXN0cl9yZW1vdmUobWNvdl9pZCwgIi0iKSkgJT4lCiAgYXJyYW5nZShDT0xMRUNUSU9OX0RUKSAlPiUgZmlsdGVyKCFkdXBsaWNhdGVkKFBhdGllbnRJRCkpCgojc2FtcGxlcyB3ZSByZWNlaXZlZCB0aGF0IHdlJ3JlIGludGVyZXN0ZWQgaW4gKERlY2VtYmVyIDIwMjAtTm92ZW1iZXIgMjAyMSkKbWNvdl9zYW1wbGVzXzEgPC0gbWNvdl9zYW1wbGVzX2FsbCAlPiUgZmlsdGVyKCF0YXhvbiAlaW4lIGR1cDY1LjY2KSAlPiUgCiAgZmlsdGVyKE1Db1ZOdW1iZXIgJWluJSBtY292X2luZm8kTUNvVk51bWJlcikgJT4lIGxlZnRfam9pbihtY292X2luZm8pCgojYWxsIHNhbXBsZXMgc2VxdWVuY2VkIGluIGVhY2ggcnVuIChpbmNsdWRpbmcgdGhvc2UgZnJvbSBvdXRzaWRlIG9mIHRoaXMgc3R1ZHkgcGVyaW9kKSAtLSBzb21ldGltZXMgcmVsZXZhbnQgZm9yIHJ1biBRQyBwdXJwb3NlcwpydW5zX2FsbF9zYW1wbGVzIDwtIGZyZWFkKCJydW5fc2FtcGxlcy5jc3YiLCBkYXRhLnRhYmxlID0gRikgJT4lIAogIG11dGF0ZShNQ29WTnVtYmVyPXN0cl9yZW1vdmUoYFNhbXBsZSBJRGAsIi0iKSwgcnVuPVJ1bikgJT4lIAogIHNlbGVjdChydW4sIE1Db1ZOdW1iZXIpCgojc3VtbWFyeSBzdGF0cyBvbiBjb3ZlcmFnZSBvZiBlYWNoIHNhbXBsZTsgZHJvcCB0aGUgcnVuIDY1IGR1cGxpY2F0ZXMgYW5kIGpvaW4gY292ZXJhZ2UgaW5mbyB0byBtYWluIGRhdGFzZXQKZDEgPSBmcmVhZCgnY292ZXJhZ2VfbGV2ZWxzXzIwMjIwNTA3LmNzdicsIGRhdGEudGFibGUgPSBGKSAlPiUgCiAgZmlsdGVyKGR1cGxpY2F0ZWQoc2FtcGxlbmFtZSkpICU+JSBwdWxsKHNhbXBsZW5hbWUpCmQyID0gZnJlYWQoJ2NvdmVyYWdlX2xldmVsc18yMDIyMDUwNy5jc3YnLCBkYXRhLnRhYmxlID0gRikgJT4lIAogIGZpbHRlcihzYW1wbGVuYW1lICVpbiUgZDEpICU+JSBmaWx0ZXIoIWR1cGxpY2F0ZWQoc2FtcGxlbmFtZSkpICU+JSAKICBwdWxsKGZpbGVuYW1lKQpjb3ZlcmFnZV9sZXZlbHMgPC0gZnJlYWQoJ2NvdmVyYWdlX2xldmVsc18yMDIyMDUwNy5jc3YnLCBkYXRhLnRhYmxlID0gRikgJT4lIAogIGZpbHRlcighZmlsZW5hbWUgJWluJSBkMikgJT4lIGZpbHRlcihzYW1wbGVuYW1lIT0iTUNvVjMwOTA0IikgJT4lIHNlbGVjdCgtMSkKYGBgCgpgYGB7cn0KIyBqb2luIGRhdGFmcmFtZXMKbWNvdl9zYW1wbGVzPC1tY292X3NhbXBsZXNfMSAlPiUgCiAgc2VsZWN0KE1Db1ZOdW1iZXIsIGxpbmVhZ2UsIHNjb3JwaW9fY2FsbCwgcWNfc3RhdHVzLCAKICAgICAgICAgQ09MTEVDVElPTl9EVCwgSU5TVFJVTUVOVCwgSU5TVFJVTUVOVF9SRVNVTFQsIHJ1bj1ydW5fZ3JvdXApICU+JSAKICBsZWZ0X2pvaW4oY292ZXJhZ2VfbGV2ZWxzLCBieT1jKCJNQ29WTnVtYmVyIj0ic2FtcGxlbmFtZSIpKQoKbWNvdl9zYW1wbGVzX3dpdGhfY3Q8LW1jb3Zfc2FtcGxlcyAlPiUgZmlsdGVyKElOU1RSVU1FTlRfUkVTVUxUPDUwKSAlPiUgCiAgbXV0YXRlKENUPUlOU1RSVU1FTlRfUkVTVUxUKQojd2hhdCdzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBDVCB2YWx1ZSBhbmQgcmVhZCBjb3ZlcmFnZT8KY292ZXJhZ2VfYWxsPC1tY292X3NhbXBsZXNfd2l0aF9jdCAlPiUgZ2dwbG90KGFlcyh4PUNULCB5PW1lZGlhbl9jb3ZlcmFnZSkpICsgCiAgZ2VvbV9wb2ludChhbHBoYT0wLjA3KSArIHRoZW1lX2J3KCkgKyB4bGFiKCJDdCB2YWx1ZSIpICsgeWxhYigiU2FtcGxlIG1lZGlhbiBkZXB0aCIpCiNob3cgZG9lcyBjb3ZlcmFnZSBpbiBoaWdoLUNUIHNhbXBsZXMgY29tcGFyZSB3aXRoIHRoZSByZXN0IG9mIHRoZW0/CmNvdmVyYWdlX2N0X2NhdDwtbWNvdl9zYW1wbGVzX3dpdGhfY3QgJT4lIG11dGF0ZShzYW1wbGVfY3Q9aWZfZWxzZShDVD49NDAsICJDVD49NDAiLCAiQ1Q8NDAiKSkgJT4lIAogIGdncGxvdChhZXMoeD1zYW1wbGVfY3QsIHk9bWVkaWFuX2NvdmVyYWdlKSkgKyAKICBnZW9tX3BvaW50KGFscGhhPTAuMiwgcG9zaXRpb249cG9zaXRpb25faml0dGVyKHdpZHRoPTAuMjUpKSArIAogIGdlb21fYm94cGxvdChjb2xvcj0icmVkIiwgYWxwaGE9MCkgKyB0aGVtZV9idygpICsgCiAgeGxhYigiQ3QgdmFsdWUiKSArIHlsYWIoIlNhbXBsZSBtZWRpYW4gZGVwdGgiKQpgYGAKCgojIyBSdW4tbGV2ZWwgUUMgCgpgYGB7cn0KI2FyZSB0aGVyZSBhbnkgcnVucyB3aGVyZSBoaWdoLUNUIHNhbXBsZXMgaGF2ZSB1bnVzdWFsbHkgaGlnaCBjb3ZlcmFnZT8gdHJlYXQgQ1Q+NDAgc2FtcGxlcyBhcyBuZWdhdGl2ZSBjb250cm9scyBhbmQgZWxpbWluYXRlIHJ1bnMgd2hlcmUgdGhlaXIgY292ZXJhZ2UgaXMgbm90IGRpZmZlcmVudCBmcm9tIHRob3NlIG9mIHRoZSByZXN0IG9mIHRoZSBzYW1wbGVzCnRlc3RfZ3JvdXA8LW1jb3Zfc2FtcGxlc193aXRoX2N0ICU+JSBtdXRhdGUoaXNfbmVnPWlmX2Vsc2UoQ1Q+PTQwLDEsMCkpICU+JSAKICBncm91cF9ieShydW4pICU+JSBtdXRhdGUobl9uZWdzPXN1bShpc19uZWcpKSAlPiUgZmlsdGVyKG5fbmVncz49MykgJT4lIAogIHVuZ3JvdXAoKSAlPiUgbXV0YXRlKHNhbXBsZXR5cGU9aWZfZWxzZShpc19uZWc9PTEsICJuZWdjdHJsIiwic2FtcGxlIikpCnJ1bnNfdG9fZHJvcDEgPSB0ZXN0X2dyb3VwICU+JSBncm91cF9ieShydW4pICU+JSAKICBzdW1tYXJpc2UodF90ZXN0X3A9dC50ZXN0KGZyYWN0aW9uXzEwMDB4X2NvdmVyYWdlfnNhbXBsZXR5cGUpJHAudmFsdWUpICU+JSAKICBhcnJhbmdlKGRlc2ModF90ZXN0X3ApKSAlPiUgZmlsdGVyKHRfdGVzdF9wPjAuMDEpICU+JSBwdWxsKHJ1bikKcnVuc190b19kcm9wMiA9IHRlc3RfZ3JvdXAgJT4lIGdyb3VwX2J5KHJ1bikgJT4lIAogIHN1bW1hcmlzZSh0X3Rlc3RfcD10LnRlc3QobWVkaWFuX2NvdmVyYWdlfnNhbXBsZXR5cGUpJHAudmFsdWUpICU+JSAKICBhcnJhbmdlKGRlc2ModF90ZXN0X3ApKSAlPiUgZmlsdGVyKHRfdGVzdF9wPjAuMDEpICU+JSBwdWxsKHJ1bikKCiMjIyMjIyMjIyMjIyAKcnVuc190b19kcm9wPC11bmlvbihydW5zX3RvX2Ryb3AxLCBydW5zX3RvX2Ryb3AyKQpzYXZlUkRTKHJ1bnNfdG9fZHJvcCwgInByb2Nlc3NpbmcvcnVuc190b19kcm9wLnJkcyIpCgptY292X3NhbXBsZXNfd2l0aF9jdCAlPiUgcHVsbChydW4pICU+JSB1bmlxdWUoKQp0ZXN0X2dyb3VwICU+JSBncm91cF9ieShydW4sIHNhbXBsZXR5cGUpICU+JSBzdW1tYXJpemUoY291bnRzID0gbigpKSAlPiUgCiAgZmlsdGVyKHJ1biAlaW4lIHJ1bnNfdG9fZHJvcCkgJT4lIG5yb3coKQoKbWNvdl9zYW1wbGVzX3dpdGhfY3QgJT4lIHB1bGwocnVuKSAlPiUgdW5pcXVlKCkKdGVzdF9ncm91cCAlPiUgZ3JvdXBfYnkocnVuLCBzYW1wbGV0eXBlKSAlPiUgc3VtbWFyaXplKGNvdW50cyA9IG4oKSkgJT4lIAogIGZpbHRlcihzYW1wbGV0eXBlPT0ibmVnY3RybCIpICU+JSBhcnJhbmdlKGNvdW50cykgJT4lIG11dGF0ZShkcm9wcGVkID0gcnVuICVpbiUgcnVuc190b19kcm9wKSAlPiUKICBnZ3Bsb3QoYWVzKGRyb3BwZWQsY291bnRzLCBsYWJlbD1ydW4pKSArIGdlb21fYm94cGxvdCgpICsgZ2VvbV9wb2ludCgpICsgZ2VvbV90ZXh0X3JlcGVsKCkgKyB0aGVtZV9wdWJyKCkKCnJ1bnNfa2VwdCA9IG1jb3Zfc2FtcGxlc193aXRoX2N0JHJ1blshbWNvdl9zYW1wbGVzX3dpdGhfY3QkcnVuICVpbiUgcnVuc190b19kcm9wXSAlPiUgdW5pcXVlKCkKCmBgYAoKYGBge3J9CmYxID0gbWNvdl9zYW1wbGVzX3dpdGhfY3QgJT4lIG11dGF0ZShydW5fa2VwdCA9IHJ1biAlaW4lIHJ1bnNfa2VwdCkgJT4lIAogIGdncGxvdChhZXMoSU5TVFJVTUVOVF9SRVNVTFQsIGZyYWN0aW9uXzEwMDB4X2NvdmVyYWdlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IHJ1bl9rZXB0KSkgKyAKICBnZW9tX3BvaW50KHNoYXBlPSIuIiwgYWxwaGEgPSAwLjUpICsgdGhlbWVfcHVicigpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNDAsIGZhY2UgPSAiYm9sZCIpKSArIAogIGdlb21fdmxpbmUoeGludGVyY2VwdD00MCwgY29sb3IgPSAicmVkIikgKyBnZW9tX3Ntb290aCgpCmYxCgpmMiA9IG1jb3Zfc2FtcGxlc193aXRoX2N0ICU+JSBtdXRhdGUocnVuX2tlcHQgPSBydW4gJWluJSBydW5zX2tlcHQpICU+JSAKICBnZ3Bsb3QoYWVzKElOU1RSVU1FTlRfUkVTVUxULCBsb2cxMChtZWRpYW5fY292ZXJhZ2UpLCBjb2xvciA9IHJ1bl9rZXB0KSkgKyAKICBnZW9tX3BvaW50KHNoYXBlPSIuIiwgYWxwaGEgPSAwLjUpICsgdGhlbWVfcHVicigpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNDAsIGZhY2UgPSAiYm9sZCIpKSArIAogIGdlb21fdmxpbmUoeGludGVyY2VwdD00MCwgY29sb3IgPSAicmVkIikgKyBnZW9tX3Ntb290aCgpCgpydW5zX3NhbXBsZXNfZG90cyA9IGdnYXJyYW5nZShmMSwgZjIsIG5jb2wgPSAxLCBucm93ID0gMiwgYWxpZ24gPSAidiIsIGNvbW1vbi5sZWdlbmQgPSBUKQpydW5zX3NhbXBsZXNfZG90cwpnZ3NhdmUoImdnc2F2ZS9ydW5zX3NhbXBsZXNfZG90cy5wZGYiLCBwbG90ID0gcnVuc19zYW1wbGVzX2RvdHMsIHdpZHRoID0gMywgaGVpZ2h0ID0gNC41KQpgYGAKCgpgYGB7cn0KbWNvdl9zYW1wbGVzX3dpdGhfY3QgJT4lIGNvbG5hbWVzKCkKYGBgCgoKYGBge3J9CiMjIyBwbG90IGJveHBsb3Qgb2YgdGhlIHJ1bnMKc3RtcCA9IG1jb3Zfc2FtcGxlc193aXRoX2N0ICU+JSBtdXRhdGUocnVuX2Ryb3BwZWQgPSBydW4gJWluJSAgIAogICAgcnVuc190b19kcm9wKSAlPiUgbXV0YXRlKHJ1biA9IGFzLm51bWVyaWMoZ3N1YigiUnVuXyIsICIiLCBydW4pKSkgJT4lIAogICAgbXV0YXRlKGlzX25lZz1pZl9lbHNlKENUPj00MCwxLDApKQoKbGFiZWxfYXQgPC0gZnVuY3Rpb24obikgZnVuY3Rpb24oeCkgaWZlbHNlKHggJSUgbiA9PSAwLCB4LCAiIikKCgpmMyA9IGdncGxvdChzdG1wLCBhZXMoeD1ydW4sIHk9ZnJhY3Rpb25fMTAwMHhfY292ZXJhZ2UsIGdyb3VwID0gcnVuLCAKICAgICAgICAgICAgIGNvbG9yID0gcnVuX2Ryb3BwZWQsIGZpbGwgPSBydW5fZHJvcHBlZCkpICsgCiAgZ2VvbV9ib3hwbG90KCkgKyAKICBnZW9tX3BvaW50KGRhdGEgPSBzdG1wICU+JSBmaWx0ZXIoaXNfbmVnID09IFQpLCAKICAgICAgICAgICAgIGFlcyhydW4sIGZyYWN0aW9uXzEwMDB4X2NvdmVyYWdlKSwgY29sb3IgPSAicmVkIiwgYWxwaGEgPSAuOSwgCiAgICAgICAgICAgICBzaGFwZSA9IDEpICsgCiAgc2NhbGVfZmlsbF9ncmV5KHN0YXJ0ID0gMSwgZW5kID0gMC44KSArIAogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMTAsOTAsMiksIGxpbWl0cyA9IGMoMTAsOTIpLCBsYWJlbHMgPSBsYWJlbF9hdCgxMCkpICsgIAogIHNjYWxlX2NvbG9yX2dyZXkoc3RhcnQ9MCwgZW5kPTAuNikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gLjUpKSArCiAgbGFicyggeCA9IE5VTEwpCiAgCmY0ID0gZ2dwbG90KHN0bXAsIGFlcyh4PXJ1biwgeT1sb2cxMChtZWRpYW5fY292ZXJhZ2UpLCBncm91cCA9IHJ1biwgCiAgICAgICAgICAgICBjb2xvciA9IHJ1bl9kcm9wcGVkLCBmaWxsID0gcnVuX2Ryb3BwZWQpKSArIAogIGdlb21fYm94cGxvdCgpICsgCiAgZ2VvbV9wb2ludChkYXRhID0gc3RtcCAlPiUgZmlsdGVyKGlzX25lZyA9PSBUKSwgCiAgICAgICAgICAgICBhZXMocnVuLCBsb2cxMChtZWRpYW5fY292ZXJhZ2UpKSwgY29sb3IgPSAicmVkIiwgYWxwaGEgPSAuOSwgCiAgICAgICAgICAgICBzaGFwZSA9IDEpICsgCiAgc2NhbGVfZmlsbF9ncmV5KHN0YXJ0ID0gMSwgZW5kID0gMC44KSArIAogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMTAsOTAsMiksIGxpbWl0cyA9IGMoMTAsOTIpLCBsYWJlbHMgPSBsYWJlbF9hdCgxMCkpICsgIAogIHNjYWxlX2NvbG9yX2dyZXkoc3RhcnQ9MCwgZW5kPTAuNikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gLjUpKSArCiAgbGFicyggeCA9IE5VTEwpCgpydW5fZmlsdGVyX3JlZCA9IGdnYXJyYW5nZShmMywgZjQsIG5jb2wgPSAxLCBucm93ID0gMiwgYWxpZ24gPSAidiIsIGNvbW1vbi5sZWdlbmQgPSBUKQooKAogIHJ1bl9maWx0ZXJfcmVkX3Bsb3QgPSBhbm5vdGF0ZV9maWd1cmUocnVuX2ZpbHRlcl9yZWQsCiAgICAgICAgICAgICAgIHRvcCA9IHRleHRfZ3JvYigicmVkIGNpcmNsZXM6IHNhbXBsZXMgQ3Q+NDAiLCBjb2xvciA9ICJyZWQiLCBzaXplID0gMTApKQopKQoKZ2dzYXZlKCJnZ3NhdmUvcnVuX2ZpbHRlcl9yZWRfcGxvdC5wZGYiLCBwbG90ID0gcnVuX2ZpbHRlcl9yZWRfcGxvdCwgd2lkdGggPSA2LCBoZWlnaHQgPSA0KQpgYGAKCiMjIFNhbXBsZS1sZXZlbCBRQwpgYGB7cn0KI25leHRjbGFkZSBRQwpuYzwtZnJlYWQoImhvdXN0b25fbmV4dGNsYWRlLnRzdiIsIHNlcD0nXHQnLCBkYXRhLnRhYmxlID0gRikgJT4lIAogIG11dGF0ZShNQ29WTnVtYmVyPXJlZ21hdGNoZXMoc2VxTmFtZSwgcmVnZXhwcigiW00sUixTLE9dQ29WLlswLTldKyIsIHNlcU5hbWUpKSAlPiUgCiAgICAgICAgICAgc3RyX3JlbW92ZSgiLSIpICU+JSBzdHJfcmVtb3ZlKCJfIikpICU+JSBmaWx0ZXIoIWR1cGxpY2F0ZWQoTUNvVk51bWJlcikpCm5leHRjbGFkZV9iYWRfc2FtcGxlczwtbmMgJT4lIGZpbHRlcihxYy5vdmVyYWxsU3RhdHVzICVpbiUgYygiYmFkIikpICU+JSBwdWxsKE1Db1ZOdW1iZXIpCiNkcm9wIGJhZCBydW5zIGFuZCBzYW1wbGVzIHRoYXQgZG9uJ3QgcGFzcyBwYW5nb2xpbiBRQyBvciBuZXh0Y2xhZGUgUUMKbWNvdl9zYW1wbGVzX2ZpbHRlcmVkPC1tY292X3NhbXBsZXMgJT4lIGZpbHRlcighcnVuICVpbiUgcnVuc190b19kcm9wKSAlPiUgCiAgZmlsdGVyKHFjX3N0YXR1cz09InBhc3MiKSAlPiUgZmlsdGVyKCFNQ29WTnVtYmVyICVpbiUgbmV4dGNsYWRlX2JhZF9zYW1wbGVzKSAlPiUgCiAgZmlsdGVyKHNjb3JwaW9fY2FsbCE9Ik9taWNyb24gKEJBLjEtbGlrZSkiKSAlPiUgCiAjIyMjIyAjbWFpbiBjb3ZlcmFnZSBjcml0ZXJpb24gZm9yIGZhaXIgY29tcGFyaXNvbnM6IFggZGVwdGggb3ZlciBZIHBlcmNlbnQgb2YgdGhlIGdlbm9tZQogIGZpbHRlcihmcmFjdGlvbl8xMDB4X2NvdmVyYWdlPj0wLjk4KSAlPiUgZHJvcGxldmVscygpCgojd2hhdCdzIHRoZSBkaXN0cmlidXRpb24gb2YgQ1QgdmFsdWVzPwpjdF9kaXN0cmlidXRpb25fYWZ0ZXJfcWM8LW1jb3Zfc2FtcGxlc19maWx0ZXJlZCAlPiUgZmlsdGVyKElOU1RSVU1FTlRfUkVTVUxUPDUwKSAlPiUgCiAgZ2dwbG90KGFlcyh4PUlOU1RSVU1FTlRfUkVTVUxUKSkgKyBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aD0xKSArIHRoZW1lX2J3KCkgKyAKICB4bGFiKCJDdCB2YWx1ZSIpICsgbGFicyhjYXB0aW9uPSJBZnRlciBleGNsdXNpb24gY3JpdGVyaWEiKQpgYGAKCmBgYHtyfQojSG93IGRpZCBleGNsdXNpb24gY3JpdGVyaWEgY2hhbmdlIGRpc3RyaWJ1dGlvbiBvZiBzYW1wbGUgQ3QgdmFsdWVzPwoKY3RfZGlzdHJpYnV0aW9uX2FmdGVyX3FjPC1tY292X3NhbXBsZXNfZmlsdGVyZWQgJT4lIGZpbHRlcihJTlNUUlVNRU5UX1JFU1VMVDw1MCkgJT4lIGdncGxvdChhZXMoeD1JTlNUUlVNRU5UX1JFU1VMVCkpICsgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGg9MSkgKyB0aGVtZV9idygpICsgeGxhYigiQ3QgdmFsdWUiKQoKY3RfZGlzdHJpYnV0aW9uX2JlZm9yZV9xYzwtbWNvdl9zYW1wbGVzICU+JSBmaWx0ZXIoSU5TVFJVTUVOVF9SRVNVTFQ8NTApICU+JSBnZ3Bsb3QoYWVzKHg9SU5TVFJVTUVOVF9SRVNVTFQpKSArIGdlb21faGlzdG9ncmFtKGJpbndpZHRoPTEpICsgdGhlbWVfYncoKSArIHhsYWIoIkN0IHZhbHVlIikgKyBsYWJzKGNhcHRpb249IkJlZm9yZSBleGNsdXNpb24gY3JpdGVyaWEiKQojY3RfaW5jbHVzaW9uPC1wbG90X2dyaWQoY3RfZGlzdHJpYnV0aW9uX2JlZm9yZV9xYywgY3RfZGlzdHJpYnV0aW9uX2FmdGVyX3FjLCBucm93PTIpCgojY3RfaW5jbHVzaW9uCgoKY3RfZGlzdHJpYnV0aW9uX2FmdGVyX3FjPC1tY292X3NhbXBsZXNfZmlsdGVyZWQgJT4lIGZpbHRlcihJTlNUUlVNRU5UX1JFU1VMVDw1MCkKY3RfZGlzdHJpYnV0aW9uX2JlZm9yZV9xYzwtbWNvdl9zYW1wbGVzICU+JSBmaWx0ZXIoSU5TVFJVTUVOVF9SRVNVTFQ8NTApCnBsb3QxX2N0X2JlZm9yZV9hZnRlciA9IGdncGxvdChhZXMoeD1JTlNUUlVNRU5UX1JFU1VMVCksIGRhdGEgPSBjdF9kaXN0cmlidXRpb25fYmVmb3JlX3FjKSArIAogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMSwgZmlsbCA9ICJncmV5IikgKwogIGdlb21faGlzdG9ncmFtKGRhdGEgPSBjdF9kaXN0cmlidXRpb25fYWZ0ZXJfcWMsIGJpbndpZHRoPTEpICsgdGhlbWVfcHVicigpICsgCiAgeGxhYigiQ3QgdmFsdWUiKSArIHlsYWIoIiMgc2FtcGxlcyIpICMrIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDI2LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgICAgIGxpbmV0eXBlID0gImRhc2hlZCIpCgpnZ3NhdmUoImdnc2F2ZS9wbG90MV9jdF9iZWZvcmVfYWZ0ZXIucGRmIiwgcGxvdDFfY3RfYmVmb3JlX2FmdGVyLCBoZWlnaHQgPSAyLCB3aWR0aCA9IDQpCmBgYAoKIyMgUHJlbGltaW5hcnkgbWlub3IgdmFyaWFudCBkaXN0cmlidXRpb25zCgpgYGB7cn0KI251Y2xlb3RpZGUgcG9zaXRpb25zIG9mIGFsbCBwcmltZXJzIHVzZWQgaW4gZGF0YXNldDsgd2lsbCBleGNsdWRlIApwcmltZXJzID0gZnJlYWQoIm5Db1YtMjAxOS5hcnRpY192My5wcmltZXIudHh0Iiwgc2VwPSJcdCIsIGhlYWRlcj1GQUxTRSwgZGF0YS50YWJsZT1GKSAlPiUgCiAgc2VsZWN0KHN0YXJ0ID0gVjIsIGVuZCA9IFYzKQpwcmltZXJfcG9zaXRpb25zX3YzPC1hcy5udW1lcmljKCkKZm9yIChpIGluIDE6bnJvdyhwcmltZXJzKSl7CiAgcHJpbWVyX3Bvc2l0aW9uc192MzwtYyhwcmltZXJfcG9zaXRpb25zX3YzLCBwcmltZXJzW2ksXSRzdGFydDpwcmltZXJzW2ksXSRlbmQpCn0KCnByaW1lcnMgPSBmcmVhZCgibkNvVi0yMDE5LmFydGljX3Y0LnByaW1lci5iZWQiLCBzZXA9Ilx0IiwgCiAgICAgICAgICAgICAgICBoZWFkZXI9RkFMU0UsIGRhdGEudGFibGUgPSBGKSAlPiUgc2VsZWN0KHN0YXJ0ID0gVjIsIGVuZCA9IFYzKQpwcmltZXJfcG9zaXRpb25zX3Y0PC1hcy5udW1lcmljKCkKZm9yIChpIGluIDE6bnJvdyhwcmltZXJzKSl7CiAgcHJpbWVyX3Bvc2l0aW9uc192NDwtYyhwcmltZXJfcG9zaXRpb25zX3Y0LCBwcmltZXJzW2ksXSRzdGFydDpwcmltZXJzW2ksXSRlbmQpCn0KCnByb2JsZW1fc2l0ZXNfZ2xvYmFsID0gZnJlYWQoInByb2JsZW1hdGljX3NpdGVzX3NhcnNDb3YyX3Y4LTIwMjExMDI3LnZjZiIsIHNraXAgPSA4OCkgJT4lCiAgZmlsdGVyKEZJTFRFUiAhPSAibWFzayIpICU+JQogIGZpbHRlcighZ3JlcGwoJ3NpbmdsZV9zcmN8bmFub3BvcmUnLCBJTkZPKSkgJT4lIHB1bGwoUE9TKQpwcm9ibGVtX3NpdGVzX2hvdXN0b24gPSBmcmVhZCgicHJvYmxlbWF0aWNfc2l0ZXNfc2Fyc0NvdjJfdjgtMjAyMTEwMjcudmNmIiwgc2tpcCA9IDg4KSAlPiUKICBmaWx0ZXIoZ3JlcGwoJ0hvdXN0b24nLCBJTkZPKSkgJT4lIHB1bGwoUE9TKQpwcm9ibGVtX3NpdGVzID0gdW5pcXVlKGMocHJvYmxlbV9zaXRlc19nbG9iYWwsIHByb2JsZW1fc2l0ZXNfaG91c3RvbikpCgpwcmltZXJfcG9zaXRpb25zX2FsbCA8LSBjKHByaW1lcl9wb3NpdGlvbnNfdjMsIHByaW1lcl9wb3NpdGlvbnNfdjQsIHByb2JsZW1fc2l0ZXMpICU+JSB1bmlxdWUoKSAKIyBpbnNlcnQgcHJvYmxlbSBzaXRlcyBpZiBuZWNlc3NhcnkKCnNhdmVSRFMocHJpbWVyX3Bvc2l0aW9uc19hbGwsICJwcmltZXJfcG9zaXRpb25zX2FsbC5yZHMiKQoKI3JlZmVyZW5jZSBnZW5vbWUgd2l0aCBudWNsZW90aWRlIHBvc2l0aW9ucyBvZiBnZW5lcwpnZW5lcyA8LSBmcmVhZCgibnRwb3NfZ2VuZV91cGRhdGUuY3N2IiwgZGF0YS50YWJsZSA9IEYpCmdlbmVfbmFtZXMgPC0gZ2VuZXMgJT4lIHB1bGwoZ2VuZV9pZCkgJT4lIHVuaXF1ZSgpCmdlbmVzJGdlbmVfaWQgPC0gZmFjdG9yKGdlbmVzJGdlbmVfaWQsIGxldmVscyA9IGdlbmVfbmFtZXMpCmBgYAoKYGBge3J9CiMjIyBVcGRhdGUgdGhpcyBpZiB5b3UgY2hhbmdlIHNhbXBsZSBpbmNsdXNpb24gY3JpdGVyaWEKIyMjIFVwZGF0ZSB0aGlzIGlmIGNoYW5nZSB0aGUgdGhyZXNob2xkcyBmb3IgY291bnRpbmcgbWlub3IgdmFyaWFudHMKI2ZpbGUgd2FzIGFscmVhZHkgZmlsdGVyZWQgdG8gc2l0ZXMgd2l0aCBtaW5pbXVtIDEwMCByZWFkcyBkZXB0aCBhbmQgQSxDLFQsRyBtaW5vciB2YXJpYW50IHByZXNlbnQgYW5kIGJpbm9taWFsIHNpZ25pZmljYW5jZSBjaGVjayBwYXNzZWQuIEZ1cnRoZXIgZmlsdGVyaW5nOgoKCiMgZGVwdGhfYXRfc2l0ZTwtMTAwCiMgbWlub3JfZnJlcXVlbmN5PC0wLjAxCiMgdG90YWxfbWlub3JfcmVhZHM8LTUwCiMgCiMgbWlub3JfdmFyaWFudF9zaXRlc190aHJlc2hvbGQgPC0gZnJlYWQoIm1pbm9yX3NpdGVzXzEwMHhfYWxsXzIwMjIwNTA3LmNzdiIpICU+JQojICAgbXV0YXRlKE1Db1ZOdW1iZXI9cmVnbWF0Y2hlcyhuYW1lLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWdleHByKCJbTSxSLFMsT11Db1YuWzAtOV0rIiwgbmFtZSkpICU+JQojICAgICAgICAgICAgc3RyX3JlbW92ZSgiLSIpICU+JSBzdHJfcmVtb3ZlKCJfIikpICU+JQojICAgZmlsdGVyKCFudHBvcyAlaW4lIHByaW1lcl9wb3NpdGlvbnNfYWxsKSAlPiUgI2Rvbid0IGluY2x1ZGUgcHJpbWVyIGJpbmRpbmcgc2l0ZXMKIyAgIGZpbHRlcihNQ29WTnVtYmVyICVpbiUgbWNvdl9zYW1wbGVzX2ZpbHRlcmVkJE1Db1ZOdW1iZXIpICU+JQojICAgZmlsdGVyKHRvdGFsY291bnQ+PWRlcHRoX2F0X3NpdGUpICU+JQojICAgZmlsdGVyKCFudHBvcyAlaW4lIGMoMToyNjUpKSAlPiUgZmlsdGVyKCFudHBvcz4yOTY3NCkgJT4lICNkb24ndCBpbmNsdWRlIDUnIGFuZCAzJyBVVFIKIyAgIGZpbHRlcihtYWpvciAlaW4lIGMoIkEiLCJDIiwiVCIsIkciKSkgJT4lICNkb24ndCB3YW50IG1pbm9yIHZhcmlhbnRzIGF0IGNvbnNlbnN1cyBkZWxldGlvbiBzaXRlcwojICAgZmlsdGVyKG1pbm9yZnJlcT49bWlub3JfZnJlcXVlbmN5KSAlPiUKIyAgIGZpbHRlcihtaW5vcmZyZXEqdG90YWxjb3VudD49dG90YWxfbWlub3JfcmVhZHMpCiMgd3JpdGVfZmVhdGhlcihtaW5vcl92YXJpYW50X3NpdGVzX3RocmVzaG9sZCwgJ3Byb2Nlc3NpbmcvbWlub3JfdmFyaWFudHNfZmlsdGVyZWRfMTAweDAuMDFfNTAuYXJyb3cnKQpgYGAKCgoKIyMgT3ZlcmFsbCBtaW5vciB2YXJpYW50IHJpY2huZXNzCgpgYGB7cn0KbWlub3JfdmFyaWFudF9zaXRlc190aHJlc2hvbGQgPC0gcmVhZF9mZWF0aGVyKCdwcm9jZXNzaW5nL21pbm9yX3ZhcmlhbnRzX2ZpbHRlcmVkXzEwMHgwLjAxXzUwLmFycm93JykgCm5fdmFyIDwtIG1pbm9yX3ZhcmlhbnRfc2l0ZXNfdGhyZXNob2xkICU+JSBncm91cF9ieShNQ29WTnVtYmVyKSAlPiUgdGFsbHkoKSAlPiUgYXJyYW5nZShkZXNjKG4pKSAjdGhpcyB0YWxseSBkb2Vzbid0IGluY2x1ZGUgYW55IHNhbXBsZXMgd2l0aCAwIHZhcmlhbnRzLCBzbyBuZWVkIHRvIGpvaW4gdG8gb3JpZ2luYWwgbGlzdApzYW1wbGVzX25fdmFyIDwtIG1jb3Zfc2FtcGxlc19maWx0ZXJlZCAlPiUgbGVmdF9qb2luKG5fdmFyKSAlPiUgCiAgYXJyYW5nZShDT0xMRUNUSU9OX0RUKSAlPiUgbXV0YXRlKG5fdmFyPXRpZHlyOjpyZXBsYWNlX25hKG4sMCkpCndyaXRlX2ZlYXRoZXIoc2FtcGxlc19uX3ZhciwgInByb2Nlc3Npbmcvc2FtcGxlc19uX3Zhci5hcnJvdyIpCgojd2hhdCdzIHRoZSBkaXN0cmlidXRpb24gb2YgbWlub3IgdmFyaWFudCByaWNobmVzcz8KIyMjIAooKAogIG5fdmFyX3NlbGVjdCA8LSBzYW1wbGVzX25fdmFyICU+JSBnZ3Bsb3QoYWVzKHg9bl92YXIpKSArIAogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoPTUpICsgdGhlbWVfcHVicigpICsgCiAgeGxhYigiTm8uIG1pbm9yIHZhcmlhbnRzIGluIHNhbXBsZSIpICsgeWxhYigiTm8uIHNhbXBsZXMiKSArIAogIHNjYWxlX3lfY29udGludW91cyh0cmFucz0nbG9nMXAnLCBicmVha3M9YygxLCAxMCwgMTAwLCAxMDAwLCA1MDAwKSkKKSkKYGBgCgpgYGB7cn0KI3doYXQncyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gbWlub3IgdmFyaWFudCByaWNobmVzcyBhbmQgQ3QgdmFsdWU/CgoKbl92YXJfc2VsZWN0X2N0ID0gc2FtcGxlc19uX3ZhciAlPiUgZmlsdGVyKElOU1RSVU1FTlRfUkVTVUxUPDUwKSAlPiUgCiAgZ2dwbG90KGFlcyh4PUlOU1RSVU1FTlRfUkVTVUxULCB5PW5fdmFyKSkgKyAKICBnZW9tX3BvaW50KHNoYXBlID0gMSwgYWxwaGEgPSAxLzgpICsgCiAgZ2VvbV9kZW5zaXR5XzJkKGFscGhhID0gMS8yLCBjb2xvciA9ICJyZWQiKSArIAogIHNjYWxlX3lfY29udGludW91cyh0cmFucyA9ICJsb2cxcCIsIGJyZWFrcyA9IGMoMCwxLDUsMTAsMzAsNTAsMTAwLDMwMCw1MDApKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLDQwLGJ5ID0gNSkpICsKICB0aGVtZV9wdWJyKCkgKyB4bGFiKCJDdCB2YWx1ZSIpICsgeWxhYigibl92YXIiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMzAsIGxpbmV0eXBlID0gImRhc2hlZCIpICsgCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMjYsIGxpbmV0eXBlID0gImRhc2hlZCIpCgpwbG90MV90YXJnZXQgPSBnZ01hcmdpbmFsKG5fdmFyX3NlbGVjdF9jdCwgdHlwZSA9ICJ2aW9saW4iLCBkcmF3X3F1YW50aWxlcyA9IAogICAgICAgICAgICAgYyguMjUsLjUsLjc1KSkKCmdnc2F2ZSgiZ2dzYXZlL3Bsb3QxX3RhcmdldC5wZGYiLCBwbG90ID0gcGxvdDFfdGFyZ2V0LCBoZWlnaHQgPSAzLCB3aWR0aCA9IDQpCgooKApuX3Zhcl9zZWxlY3RfY3RfZmlsdGVyZWQgPSBzYW1wbGVzX25fdmFyICU+JSAKICBmaWx0ZXIoSU5TVFJVTUVOVF9SRVNVTFQ8MjYgJiBuX3ZhciA8IDMwKSAlPiUgCiAgZ2dwbG90KGFlcyh4PUlOU1RSVU1FTlRfUkVTVUxULCB5PW5fdmFyKSkgKyAKICBnZW9tX3BvaW50KHNoYXBlID0gMSwgYWxwaGEgPSAxLzE2KSArIAogIGdlb21fZGVuc2l0eV8yZChjb2xvciA9ICJzYWxtb24iKSArIAogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwzMCw1KSkgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMCw0MCxieSA9IDUpKSArCiAgdGhlbWVfcHVicigpICsgeGxhYigiQ3QgdmFsdWUiKSArIHlsYWIoIm5fdmFyIikgKwogIGdlb21fc21vb3RoKGNvbG9yID0gInJlZCIpICsgc3RhdF9jb3IobWV0aG9kID0gInNwZWFybWFuIiwgY29yLmNvZWYubmFtZSA9ICJyaG8iKQopKQoKcGF0aWVudF9vcmRpbmFsX2NvdW50cyA9IHNhbXBsZXNfbl92YXIgJT4lIAogIGZpbHRlcihJTlNUUlVNRU5UX1JFU1VMVDwyNiAmIG5fdmFyIDwgMzApICU+JSAKICBtdXRhdGUob3JkaW5hbF9jb3VudHMgPSBjdXQobl92YXIsIGJyZWFrcyA9IHNlcSgwLDMwLDUpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmlnaHQgPSBGKSkgJT4lIAogIHNlbGVjdChuX3Zhciwgb3JkaW5hbF9jb3VudHMpICU+JSBhcnJhbmdlKG5fdmFyKSAlPiUgCiAgZ3JvdXBfYnkob3JkaW5hbF9jb3VudHMpICU+JSBzdW1tYXJpemUoY291bnRzID0gbigpKSAlPiUgCiAgbXV0YXRlKHBvc2l0aW9uID0gc2VxKDIuNSwyNy41LDUpKQoKbl92YXJfc2VsZWN0X2N0X2ZpbHRlcmVkX2xhYmVsZWQgPSBuX3Zhcl9zZWxlY3RfY3RfZmlsdGVyZWQgKwogIGdlb21fdGV4dChhZXMoeD0yNSwgeSA9IHBvc2l0aW9uLCBsYWJlbCA9IGNvdW50cyksIGNvbG9yID0gImRhcmtibHVlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gcGF0aWVudF9vcmRpbmFsX2NvdW50cykgKwogIHRoZW1lX21pbmltYWxfaGdyaWQoKQoKY3Rfbl92YXJfcG9zdGZpbHRlcl9wbG90ID0gZ2dNYXJnaW5hbChuX3Zhcl9zZWxlY3RfY3RfZmlsdGVyZWRfbGFiZWxlZCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJ2aW9saW4iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcmF3X3F1YW50aWxlcyA9IGMoMC4yNSwwLjUsMC43NSkpCmN0X25fdmFyX3Bvc3RmaWx0ZXJfcGxvdAoKCmdnc2F2ZSgiZ2dzYXZlL2N0X25fdmFyX3Bvc3RmaWx0ZXJfcGxvdC5wZGYiLCAKICAgICAgIGN0X25fdmFyX3Bvc3RmaWx0ZXJfcGxvdCwgaGVpZ2h0ID0gMywgd2lkdGggPSAzKQoKc2F2ZVJEUyhjdF9uX3Zhcl9wb3N0ZmlsdGVyX3Bsb3QsICJjdF9uX3Zhcl9wb3N0ZmlsdGVyX3Bsb3QucmRzIikKYGBgCgpgYGB7cn0KIyBRdWFudGlsZSBpbmZvcm1hdGlvbiBmb3IgdGhlIHZpb2xpbiBwbG90IGFib3ZlCnByaW50KHNhbXBsZXNfbl92YXIgJT4lIAogIGZpbHRlcihJTlNUUlVNRU5UX1JFU1VMVDwyNiAmIG5fdmFyIDwgMzApICU+JSBwdWxsKG5fdmFyKSAlPiUgcXVhbnRpbGUoLixwcm9icyA9IGMoMCwwLjI1LDAuNSwwLjc1KSkpCgpwcmludChzYW1wbGVzX25fdmFyICU+JSAKICBmaWx0ZXIoSU5TVFJVTUVOVF9SRVNVTFQ8MjYgJiBuX3ZhciA8IDMwKSAlPiUgcHVsbChJTlNUUlVNRU5UX1JFU1VMVCkgJT4lIHF1YW50aWxlKC4scHJvYnMgPSBjKDAsMC4yNSwwLjUsMC43NSkpKQpgYGAKCmBgYHtyfQpzYW1wbGVzX25fdmFyICU+JSBwdWxsKG5fdmFyKSAlPiUgc3VtbWFyeSgpCmBgYAoKIyMgUmVwcm9kdWNpYmlsaXR5IG9mIG1pbm9yIHZhcmlhbnRzCgoKYGBge3J9Cm1pbm9yc190YWJsZTwtIGZyZWFkKCJyZXBsaWNhdGVkX3NhbXBsZXMuY3N2IiwgZGF0YS50YWJsZT1GKSAlPiUgCiAgZmlsdGVyKE1Db1ZOdW1iZXIgJWluJSBzYW1wbGVzX25fdmFyJE1Db1ZOdW1iZXIpICU+JSAKICBmaWx0ZXIobWFqb3Iub3JpZ2luYWwgJWluJSBjKCJBIiwiQyIsIlQiLCJHIikpICU+JSAKICBmaWx0ZXIobWlub3Iub3JpZ2luYWwgJWluJSBjKCJBIiwiQyIsIlQiLCJHIikpICU+JQogIGZpbHRlcih0b3RhbGNvdW50Lm9yaWdpbmFsPj0xMDAgJiBtaW5vcmZyZXEub3JpZ2luYWw+PTAuMDEgJiB0b3RhbGNvdW50Lm9yaWdpbmFsKm1pbm9yZnJlcS5vcmlnaW5hbD49NTAgJiAKICAgICAgICAgICB0b2xvd2VyKGJpbm9jaGVjay5vcmlnaW5hbCkhPSJmYWxzZSIpICU+JSBmaWx0ZXIoKCFudHBvcyAlaW4lIHByaW1lcl9wb3NpdGlvbnNfYWxsKSkgJT4lIAogIGZpbHRlcighbnRwb3MgJWluJSAxOjI2NSkgJT4lIGZpbHRlcighbnRwb3M+Mjk2NzQpCiN3YXMgdGhlIHNhbWUgbWlub3IgdmFyaWFudCBmb3VuZCBpbiB0aGUgc2Vjb25kIHJlcGxpY2F0ZT8gaWYgbm90LCBzZXQgbWlub3IgZnJlcXVlbmN5IHRvIDAgaW4gc2Vjb25kIHJlcAptaW5vcnNfdGFibGU8LW1pbm9yc190YWJsZSAlPiUgCiAgbXV0YXRlKG1pbm9yZnJlcS5yZXNlcT1pZl9lbHNlKG1pbm9yLm9yaWdpbmFsPT1taW5vci5yZXNlcSwgbWlub3JmcmVxLnJlc2VxLCAwKSkgJT4lIAogIG11dGF0ZShkZXRlY3RlZF9taW5vcl9pbl9yZXBsPWlmX2Vsc2UobWlub3Iub3JpZ2luYWw9PW1pbm9yLnJlc2VxLCJ5ZXMiLCJubyIpKQoKd3JpdGVfZmVhdGhlcihtaW5vcnNfdGFibGUsICJwcm9jZXNzaW5nL21pbm9yc190YWJsZS5hcnJvdyIpCmBgYAoKYGBge3J9CiNob3cgd2VsbCBhcmUgbWlub3IgdmFyaWFudHMgcmVjb3ZlcmVkIGluIHNhbXBsZXMgd2l0aCBkaWZmZXJlbnQgQ3QgdmFsdWVzPwptaW5vcnNfdGFibGUgPC0gbWlub3JzX3RhYmxlICU+JSBsZWZ0X2pvaW4oc2VsZWN0KG1jb3Zfc2FtcGxlcywgTUNvVk51bWJlciwgQ1Q9SU5TVFJVTUVOVF9SRVNVTFQpKSAlPiUgCiAgbXV0YXRlKHNhbXBsZUNUX2JpbiA9IGNhc2Vfd2hlbihDVDwyNiB+ICJiZWxvdyAyNiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ1Q+PTI2JkNUPD0zNSB+IkNUIDI2LTM1IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDVD4zNSZDVDw1MCB+ImdyZWF0ZXIgdGhhbiAzNSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ1Q+MTAwfiJ1bmtub3duIiwgI2FwdGltYSBpbnN0cnVtZW50IHVzZXMgUkxVIG5vdCBDVAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlzLm5hKENUKSB+ICJ1bmtub3duIikpIAooKAogIHJlcF9jdDwtbWlub3JzX3RhYmxlICU+JSAKICBnZ3Bsb3QoYWVzKHg9bWlub3JmcmVxLm9yaWdpbmFsLCB5PW1pbm9yZnJlcS5yZXNlcSwgY29sb3I9ZGV0ZWN0ZWRfbWlub3JfaW5fcmVwbCkpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJyZWQiLCJibGFjayIpKSArIGdlb21fcG9pbnQoYWxwaGE9MC41KSArIAogIGZhY2V0X3dyYXAofnNhbXBsZUNUX2JpbikgKyB0aGVtZV9idygpICsgbGFicyh4PSJNQUYgaW4gcmVwbGljYXRlIDEiLCB5PSJNQUYgaW4gcmVwbGljYXRlIDIiKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIikKKSkKCmBgYAoKYGBge3J9CiNob3cgd2VsbCBhcmUgbWlub3IgdmFyaWFudHMgcmVjb3ZlcmVkIGluIHNhbXBsZXMgd2l0aCBkaWZmZXJlbnQgbWVkaWFuIGNvdmVyYWdlPwpyZXBfZGVwdGggPC0gbWlub3JzX3RhYmxlICU+JSBsZWZ0X2pvaW4oY292ZXJhZ2VfbGV2ZWxzLCBieT1jKCJNQ29WTnVtYmVyIj0ic2FtcGxlbmFtZSIpKSAlPiUgCiAgbXV0YXRlKGNvdmVyYWdlX2Jpbj1jdXQobWVkaWFuX2NvdmVyYWdlLCA0KSkgJT4lIAogIGdncGxvdChhZXMoeD1taW5vcmZyZXEub3JpZ2luYWwsIHk9bWlub3JmcmVxLnJlc2VxLCBjb2xvcj1kZXRlY3RlZF9taW5vcl9pbl9yZXBsKSkgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoInJlZCIsImJsYWNrIikpICsgZ2VvbV9wb2ludChhbHBoYT0wLjUpICsgCiAgZmFjZXRfd3JhcCh+Y292ZXJhZ2VfYmluKSArIHRoZW1lX2J3KCkgKyAKICBsYWJzKHg9Ik1BRiBpbiByZXBsaWNhdGUgMSIsIHk9Ik1BRiBpbiByZXBsaWNhdGUgMiIpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiwgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoY29sb3I9YygxLDAsMSwwKSkpICsgCiAgbGFicyhjYXB0aW9uPSJSZXByb2R1Y2liaWxpdHkgaW4gc2FtcGxlcyB3aXRoIGRpZmZlcmVudCBtZWRpYW4gZGVwdGhzIikKI2luIHRoZSByYW5nZSBvZiBDdCB2YWx1ZXMvY292ZXJhZ2Ugb2JzZXJ2ZWQgaGVyZSwgcmVwcm9kdWNpYmlsaXR5IHNlZW1zIG1vcmUgYXNzb2NpYXRlZCB3aXRoIEN0IHRoYW4gd2l0aCBjb3ZlcmFnZSAKYGBgCgpgYGB7cn0KI3doYXQncyB0aGUgZGlzdHJpYnV0aW9uIG9mIGRlcHRoL01BRiBpbiByZXByb2R1Y2libGUgdnMuIG5vbi1yZXByb2R1Y2libGUgbWlub3IgdmFyaWFudHM/CnJlcF9kZXB0aF9mcmVxIDwtIG1pbm9yc190YWJsZSAlPiUgZ2dwbG90KGFlcyh4PXRvdGFsY291bnQub3JpZ2luYWwsIHk9bWlub3JmcmVxLm9yaWdpbmFsKSkgKyAKICBnZW9tX3BvaW50KGFscGhhPTAuNSkgKyBmYWNldF9ncmlkKGRldGVjdGVkX21pbm9yX2luX3JlcGx+LikgKyB0aGVtZV9idygpICsgCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoY29sb3I9YygxLDAsMSwwKSkpICsgeGxhYigiU2VxIGRlcHRoIGluIHJlcCAxIikgKyAKICB5bGFiKCJNQUYgaW4gcmVwIDEiKSArIGxhYnMoY2FwdGlvbj0iUmVwcm9kdWNpYmlsaXR5IGF0IHNpdGVzIHdpdGggZGlmZmVyZW50IGRlcHRoIGFuZCBNQUYiKQojZGVwdGggYW5kIGZyZXF1ZW5jeSBvZiBtaW5vciB2YXJpYW50cyBpcyBhbHNvIG5vdCB2ZXJ5IGRpZmZlcmVudCBiZXR3ZWVuIHJlcHJvZHVjaWJsZSBhbmQgbm9uLXJlcHJvZHVjaWJsZSB2YXJpYW50cwpgYGAKCmBgYHtyfQpyZXBfbXV0YXRpb25zIDwtIG1pbm9yc190YWJsZSAlPiUgZmlsdGVyKGRldGVjdGVkX21pbm9yX2luX3JlcGw9PSJ5ZXMiKSAKbm9ucmVwX211dGF0aW9ucyA8LSBtaW5vcnNfdGFibGUgJT4lIGZpbHRlcihkZXRlY3RlZF9taW5vcl9pbl9yZXBsPT0ibm8iKSAKCnBsb3RfcmVwcm9kdWNpYmxlX3NwZWN0cmFfaGVhdG1hcCA8LSB0YWJsZShyZXBfbXV0YXRpb25zJG1ham9yLm9yaWdpbmFsLCByZXBfbXV0YXRpb25zJG1pbm9yLm9yaWdpbmFsKSAlPiUgCiAgZGF0YS5mcmFtZSgpICU+JSBnZ3Bsb3QoYWVzKHg9VmFyMSwgeT1WYXIyLCBmaWxsPUZyZXEvc3VtKEZyZXEpKSkgKyAKICBnZW9tX3RpbGUoY29sb3VyID0gImJsYWNrIikgKyAjIGdyaWQgY29sb3VyCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAid2hpdGUiLAogICAgICAgICAgICAgICAgICAgICAgaGlnaCA9ICJkYXJrYmx1ZSIpICsKICB0aGVtZV9taW5pbWFsKCkgKyBsYWJzKGZpbGwgPSAiRnJhY3Rpb24iLAogICAgICAgeCA9ICJDb25zZW5zdXMgYWxsZWxlIiwKICAgICAgIHkgPSAiTWlub3IgYWxsZWxlIiwgdGl0bGU9IlJlcHJvZHVjaWJsZSIpCgoKcGxvdF9ub25yZXByb2R1Y2libGVfc3BlY3RyYV9oZWF0bWFwIDwtIHRhYmxlKG5vbnJlcF9tdXRhdGlvbnMkbWFqb3Iub3JpZ2luYWwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub25yZXBfbXV0YXRpb25zJG1pbm9yLm9yaWdpbmFsKSAlPiUgCiAgZGF0YS5mcmFtZSgpICU+JSBnZ3Bsb3QoYWVzKHg9VmFyMSwgeT1WYXIyLCBmaWxsPUZyZXEvc3VtKEZyZXEpKSkgKyAKICBnZW9tX3RpbGUoY29sb3VyID0gImJsYWNrIikgKyAKICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICJ3aGl0ZSIsCiAgICAgICAgICAgICAgICAgICAgICBoaWdoID0gImRhcmtibHVlIikgKwogIHRoZW1lX21pbmltYWwoKSArIGxhYnMoZmlsbCA9ICJGcmFjdGlvbiIsCiAgICAgICB4ID0gIkNvbnNlbnN1cyBhbGxlbGUiLAogICAgICAgeSA9ICJNaW5vciBhbGxlbGUiLCB0aXRsZT0iTm9uLXJlcHJvZHVjaWJsZSIpCgpzYXZlUkRTKHBsb3Rfbm9ucmVwcm9kdWNpYmxlX3NwZWN0cmFfaGVhdG1hcCwgZmlsZSA9ICJwbG90X25vbnJlcHJvZHVjaWJsZV9zcGVjdHJhX2hlYXRtYXAucmRzIikKc2F2ZVJEUyhwbG90X3JlcHJvZHVjaWJsZV9zcGVjdHJhX2hlYXRtYXAsIGZpbGUgPSAicGxvdF9yZXByb2R1Y2libGVfc3BlY3RyYV9oZWF0bWFwLnJkcyIpCgojIFBsb3R0ZWQgaW4gUk1EIDAzLgpgYGAKCgpgYGB7cn0KcmVwX2luZGl2X3NhbXBsZXMgPC0gbWlub3JzX3RhYmxlICU+JSBnZ3Bsb3QoYWVzKHg9bWlub3JmcmVxLm9yaWdpbmFsLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PW1pbm9yZnJlcS5yZXNlcSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3I9ZGV0ZWN0ZWRfbWlub3JfaW5fcmVwbCkpICsgCiAgZ2VvbV9wb2ludChhbHBoYT0wLjUpICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJyZWQiLCJibGFjayIpKSArIAogIGZhY2V0X3dyYXAoQ1R+TUNvVk51bWJlcikgKyB0aGVtZV9idygpICsgeGxhYigiTUFGIGluIHJlcGxpY2F0ZSAxIikgKyAKICB5bGFiKCJNQUYgaW4gcmVwbGljYXRlIDIiKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG9yPWMoMSwwLDEsMCkpKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gMTB9CiNTVVBQIEZJRyAxCnJlcGxpY2F0ZV9tZWdhX3Bsb3QgPSBwbG90X2dyaWQoCiAgcGxvdF9ncmlkKHJlcF9jdCwgCiAgICAgICAgICAgIHBsb3RfZ3JpZChyZXBfZGVwdGgsIHJlcF9kZXB0aF9mcmVxLCBuY29sPTIsIHJlbF93aWR0aHM9YygxLjIsMSksIAogICAgICAgICAgICAgICAgICAgICAgbGFiZWxzPWMoImIiLCJjIikpLCBucm93PTIsIGxhYmVscz1jKCJhIixOQSkpLCAKICByZXBfaW5kaXZfc2FtcGxlcywgbGFiZWxzPWMoTkEsICJkIiksIHJlbF93aWR0aHM9YygxLjEsMSkpCgpnZ3NhdmUoImdnc2F2ZS9yZXBsaWNhdGVfbWVnYV9wbG90LnBkZiIsIHBsb3QgPSByZXBsaWNhdGVfbWVnYV9wbG90LCBoZWlnaHQgPSA4LCB3aWR0aCA9IDE0LjUpCgpgYGAKCgpXaWxsIGxpbWl0IGFuYWx5c2VzIHRvIHNhbXBsZXMgd2l0aCBDVDwyNiwgd2hlcmUgd2UgYXJlIG1vcmUgY29uZmlkZW50IGluIHJlcHJvZHVjaWJpbGl0eSBvZiBtaW5vciB2YXJpYW50CgoKYGBge3J9CnNhbXBsZXNfbl92YXIgJT4lIGZpbHRlcihJTlNUUlVNRU5UX1JFU1VMVDwyNiAmIG5fdmFyIDwgMzApICU+JSBwdWxsKG5fdmFyKSAlPiUgcXVhbnRpbGUoYygwLjUsMC43KSkKYGBgCgpgYGB7cn0Kc2FtcGxlc190b19hbmFseXplIDwtIHNhbXBsZXNfbl92YXIgJT4lIGZpbHRlcihJTlNUUlVNRU5UX1JFU1VMVDwyNiAmIG5fdmFyIDwgMzApICU+JSBwdWxsKE1Db1ZOdW1iZXIpCmxpbmVhZ2VzX2ZpZ3VyZSA8LSBtY292X3NhbXBsZXNfZmlsdGVyZWQgJT4lIAogIGZpbHRlcihNQ29WTnVtYmVyICVpbiUgc2FtcGxlc190b19hbmFseXplKSAlPiUgCiAgbXV0YXRlKHZhcmlhbnQ9Y2FzZV93aGVuKHN0YXJ0c1dpdGgoc2NvcnBpb19jYWxsLCJEZWx0YSIpIH4gIkRlbHRhIiwKICAgICAgICBzdGFydHNXaXRoKHNjb3JwaW9fY2FsbCwiQWxwaGEiKSB+ICJBbHBoYSIsCiAgICAgICAgIShzdGFydHNXaXRoKHNjb3JwaW9fY2FsbCwiRGVsdGEiKXwKICAgICAgICAgICAgc3RhcnRzV2l0aChzY29ycGlvX2NhbGwsIkFscGhhIikpIH4gIm90aGVyIikpICU+JQogIG11dGF0ZSh2YXJpYW50PWlmX2Vsc2UobGluZWFnZSA9PSAiQi4xLjIiLCJCLjEuMiIsdmFyaWFudCkpICU+JQogIG11dGF0ZShtb250aCA9IGZsb29yX2RhdGUoQ09MTEVDVElPTl9EVCwgIm1vbnRoIikpICU+JQogIGdncGxvdChhZXMoeD1tb250aCkpICsgZ2VvbV9iYXIoYWVzKGZpbGw9dmFyaWFudCkpICArIAojICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiIzAwQTA4QSIsICIjRjJBRDAwIiwgIiNGOTg0MDAiLCAiIzVCQkNENiIpKSArIAogIHhsYWIoIkNvbGxlY3Rpb24gZGF0ZSIpICsgeWxhYigiTm8uIHNhbXBsZXMiKSArICAgc2NhbGVfeF9kYXRlKGxhYmVscyA9IGRhdGVfZm9ybWF0KCIlbS0lWSIpKSArCiAgZ2d0aXRsZShwYXN0ZTAoJ0ZpbmFsIHNhbXBsZSBzZXQsIFxuIEN0PDI2ICYgbl92YXI8MzAsIG4gPSAnLGxlbmd0aChzYW1wbGVzX3RvX2FuYWx5emUpKSkgKyAKICBzY2FsZV94X2RhdGUobWlub3JfYnJlYWtzPSIxIG1vbnRoIikgKyB0aGVtZV9wdWJyKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gLjUpLCBsZWdlbmQucG9zaXRpb24gPSAidG9wIikKCiNTVVBQIEZJRyAyCmxpbmVhZ2VzX2ZpZ3VyZQpzYXZlUkRTKGxpbmVhZ2VzX2ZpZ3VyZSwgImdnc2F2ZS9saW5lYWdlc19maWd1cmUucmRzIikKYGBgCgpgYGB7cn0Kc2FtcGxlc19uX3ZhciAlPiUgZmlsdGVyKElOU1RSVU1FTlRfUkVTVUxUPDI2KSAlPiUgcHVsbChuX3ZhcikgJT4lIHN1bW1hcnkoKQpgYGAKCmBgYHtyfQojcGxvdF9ncmlkKGNvdmVyYWdlX3ByZV9maWx0ZXJpbmcsIGN0X2luY2x1c2lvbiwgbmNvbD0yLCBsYWJlbHM9YygiYSIsImIiKSkKYGBgCgpgYGB7cn0KbWlub3Jfc2l0ZXNfbG93Y3Q8LW1pbm9yX3ZhcmlhbnRfc2l0ZXNfdGhyZXNob2xkICU+JSBsZWZ0X2pvaW4obWNvdl9zYW1wbGVzX2ZpbHRlcmVkKSAlPiUgCiAgZmlsdGVyKElOU1RSVU1FTlRfUkVTVUxUPDI2KSAKYGBgCgoKIyBXaGF0IGtpbmRzIG9mIHJ1bi1zcGVjaWZpYyBlZmZlY3RzIGRvIHdlIHNlZSBldmVuIGFmdGVyIGZpbHRlcmluZyBmb3IgaGlnaC1xdWFsaXR5IHNhbXBsZXM/CgpgYGB7cn0KI2FyZSBydW4gZWZmZWN0cyByZWxhdGVkIHRvIHNlcXVlbmNpbmcgZGVwdGg/Cm5fdmFyX2J5X2NvdmVyYWdlPC1zYW1wbGVzX25fdmFyICU+JSBmaWx0ZXIoSU5TVFJVTUVOVF9SRVNVTFQ8MjYgJiBuX3ZhciA8IDMwKSAlPiUgZ2dwbG90KGFlcyh4PW1lZGlhbl9jb3ZlcmFnZSwgeT1uX3ZhcikpICsgZ2VvbV9wb2ludChhbHBoYT0wLjA1KSArIAogIGdlb21fZGVuc2l0eV8yZChjb2xvciA9ICJzYWxtb24iKSArIGdlb21fc21vb3RoKGNvbG9yID0gInJlZCIpICsgdGhlbWVfcHVicigpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAxNTAwMCkpICsKICB4bGFiKCJTYW1wbGUgbWVkaWFuIGNvdmVyYWdlIikgKyB5bGFiKCJuX3ZhciIpICsgc3RhdF9jb3IobWV0aG9kID0gInNwZWFybWFuIiwgY29yLmNvZWYubmFtZSA9ICJyaG8iKQpuX3Zhcl9ieV9jb3ZlcmFnZQojbm90IG9uIHRoZSBpbmRpdmlkdWFsIHNhbXBsZSBsZXZlbAoKI2lzIGF2ZXJhZ2UgbWlub3IgdmFyaWFudCByaWNobmVzcyBpbiBhIHJ1biByZWxhdGVkIHRvIGF2ZXJhZ2UgZGVwdGggb2YgY292ZXJhZ2UgaW4gdGhlIHJ1bj8Kbl92YXJfZGVwdGhfYXZlcmFnZXM8LXNhbXBsZXNfbl92YXIgJT4lIGZpbHRlcihJTlNUUlVNRU5UX1JFU1VMVDwyNiAmIG5fdmFyIDwgMzApICU+JSAKICBncm91cF9ieShydW4pICU+JSAKICBzdW1tYXJpc2UobWVkaWFuX25fdmFyPW1lZGlhbihuX3ZhciksIAogICAgICAgICAgICBtZWRpYW5fc2FtcGxlX2NvdmVyYWdlPW1lZGlhbihtZWRpYW5fY292ZXJhZ2UpLCAKICAgICAgICAgICAgbWVkaWFuX2N0PW1lZGlhbihJTlNUUlVNRU5UX1JFU1VMVCkpICU+JSAKICBnZ3Bsb3QoYWVzKHg9bWVkaWFuX3NhbXBsZV9jb3ZlcmFnZSwgeT1tZWRpYW5fbl92YXIpKSArIGdlb21fcG9pbnQoYWxwaGEgPSAwLjUpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAxNTAwMCkpICsKICB0aGVtZV9wdWJyKCkgKyB4bGFiKCJSdW4gbWVkaWFuIG9mIG1lZGlhbiBjb3ZlcmFnZSIpICsgeWxhYigiUnVuIG1lZGlhbiBuX3ZhciIpICsgCiAgZ2VvbV9zbW9vdGgoY29sb3IgPSAicmVkIikgKyBzdGF0X2NvcihtZXRob2QgPSAic3BlYXJtYW4iLCBjb3IuY29lZi5uYW1lID0gInJobyIpCm5fdmFyX2RlcHRoX2F2ZXJhZ2VzCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQgPSA1LCBmaWcud2lkdGggPSA0fQpuX3Zhcl9ieV9ydW4gPC0gc2FtcGxlc19uX3ZhciAlPiUgbXV0YXRlKHJ1biA9IGFzLm51bWVyaWMoc3RyX3JlbW92ZShydW4sICJSdW5fIikpKSAlPiUgCiAgZmlsdGVyKElOU1RSVU1FTlRfUkVTVUxUIDwgMjYgJiBuX3ZhciA8IDMwKSAlPiUgCiAgICBnZ3Bsb3QoYWVzKHg9cnVuLCB5PW5fdmFyLCBncm91cCA9IHJ1bikpICsgZ2VvbV9ib3hwbG90KCkgKyAKICAgIHNjYWxlX2ZpbGxfZ3JleShzdGFydCA9IDEsIGVuZCA9IDAuOCkgKyAKICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMTAsOTAsMiksIGxpbWl0cyA9IGMoMTAsOTIpLCBsYWJlbHMgPSBsYWJlbF9hdCgxMCkpICsKICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwzMCwyKSwgbGFiZWxzID0gbGFiZWxfYXQoMTApKSArCgogICAgc2NhbGVfY29sb3JfZ3JleShzdGFydD0wLCBlbmQ9MC42KSArIAogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAuNSkpCgpwbG90c19ieV9ydW4gPSBnZ2FycmFuZ2UoZjMsIGY0LCBuX3Zhcl9ieV9ydW4sIGxhYmVscyA9IGxpc3QoIkEiLCJCIiwiRCIpLCAKICAgICAgICAgIG5jb2wgPSAxLCBucm93ID0gMywgYWxpZ24gPSAidiIsIGNvbW1vbi5sZWdlbmQgPSBUKSAlPiUgYW5ub3RhdGVfZmlndXJlKC4sCiAgICAgICAgICAgICAgIHRvcCA9IHRleHRfZ3JvYigicmVkIGNpcmNsZXM6IHNhbXBsZXMgQ3Q+NDAiLCBjb2xvciA9ICJyZWQiLCBzaXplID0gMTApKQoKZG90c19kZXB0aF9tZWRpYW4gPSBnZ2FycmFuZ2Uobl92YXJfYnlfY292ZXJhZ2UsIG5fdmFyX2RlcHRoX2F2ZXJhZ2VzLCAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGxpc3QoIkUiLCAiRiIpLCBuY29sID0gMSkKCmRvdHNfcGxvdHMgPSBnZ2FycmFuZ2UocnVuc19zYW1wbGVzX2RvdHMsIGRvdHNfZGVwdGhfbWVkaWFuLCBsYWJlbHMgPSBsaXN0KCJDIiksIAogICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAxLCBoZWlnaHRzID0gYygxLDEpKQoKcnVuX2ZpbHRyYXRpb24gPSBnZ2FycmFuZ2UocGxvdHNfYnlfcnVuLCBkb3RzX3Bsb3RzLCBuY29sID0gMiwgd2lkdGhzID0gYygyLjUsIDEpKQpydW5fZmlsdHJhdGlvbgpnZ3NhdmUoImdnc2F2ZS9ydW5fZmlsdHJhdGlvbi5wZGYiLCBydW5fZmlsdHJhdGlvbiwgaGVpZ2h0ID0gOCwgd2lkdGggPSAxMikKYGBgCg==